diff --git a/src/main/java/eu/ztsh/wymiana/exception/UserNotFoundException.java b/src/main/java/eu/ztsh/wymiana/exception/UserNotFoundException.java
new file mode 100644
index 0000000..7390eb3
--- /dev/null
+++ b/src/main/java/eu/ztsh/wymiana/exception/UserNotFoundException.java
@@ -0,0 +1,11 @@
+package eu.ztsh.wymiana.exception;
+
+import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest;
+
+public class UserNotFoundException extends RuntimeException {
+
+    public UserNotFoundException(CurrencyExchangeRequest entity) {
+        super("User with PESEL %s not found".formatted(entity.pesel()));
+    }
+
+}
diff --git a/src/main/java/eu/ztsh/wymiana/service/CurrencyService.java b/src/main/java/eu/ztsh/wymiana/service/CurrencyService.java
index b00f761..401626a 100644
--- a/src/main/java/eu/ztsh/wymiana/service/CurrencyService.java
+++ b/src/main/java/eu/ztsh/wymiana/service/CurrencyService.java
@@ -2,6 +2,7 @@ package eu.ztsh.wymiana.service;
 
 import eu.ztsh.wymiana.exception.ExchangeFailedException;
 import eu.ztsh.wymiana.exception.InsufficientFundsException;
+import eu.ztsh.wymiana.exception.UserNotFoundException;
 import eu.ztsh.wymiana.model.Currency;
 import eu.ztsh.wymiana.model.User;
 import eu.ztsh.wymiana.validation.InstanceValidator;
@@ -49,7 +50,7 @@ public class CurrencyService {
                 user.currencies().putAll(exchanged);
                 return userService.update(user);
             })
-            .orElseThrow(ExchangeFailedException::new);
+            .orElseThrow(() -> new UserNotFoundException(request));
     }
 
     private Currency create(String symbol) {
diff --git a/src/main/java/eu/ztsh/wymiana/service/UserService.java b/src/main/java/eu/ztsh/wymiana/service/UserService.java
index 0bb7945..857bc0f 100644
--- a/src/main/java/eu/ztsh/wymiana/service/UserService.java
+++ b/src/main/java/eu/ztsh/wymiana/service/UserService.java
@@ -9,9 +9,11 @@ import eu.ztsh.wymiana.web.model.UserCreateRequest;
 import lombok.RequiredArgsConstructor;
 import org.hibernate.validator.constraints.pl.PESEL;
 import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
 
 import java.util.Optional;
 
+@Validated
 @RequiredArgsConstructor
 @Service
 public class UserService {
diff --git a/src/main/java/eu/ztsh/wymiana/web/controller/ExchangeController.java b/src/main/java/eu/ztsh/wymiana/web/controller/ExchangeController.java
new file mode 100644
index 0000000..ae666ef
--- /dev/null
+++ b/src/main/java/eu/ztsh/wymiana/web/controller/ExchangeController.java
@@ -0,0 +1,42 @@
+package eu.ztsh.wymiana.web.controller;
+
+import eu.ztsh.wymiana.exception.InsufficientFundsException;
+import eu.ztsh.wymiana.exception.UserAlreadyExistsException;
+import eu.ztsh.wymiana.exception.UserNotFoundException;
+import eu.ztsh.wymiana.service.CurrencyService;
+import eu.ztsh.wymiana.validation.ValidationFailedException;
+import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequiredArgsConstructor
+@Validated
+@RestController
+@RequestMapping(path = "/api/exchange", produces = "application/json")
+public class ExchangeController {
+
+    private final CurrencyService currencyService;
+
+    @PostMapping
+    public ResponseEntity<Object> exchange(@Valid @RequestBody CurrencyExchangeRequest request) {
+        try {
+            return ResponseEntity.status(200).body(currencyService.exchange(request));
+        } catch (Exception e) {
+            var status = switch (e) {
+                case InsufficientFundsException ignored -> HttpStatus.BAD_REQUEST;
+                case UserNotFoundException ignored -> HttpStatus.NOT_FOUND;
+                default -> HttpStatus.INTERNAL_SERVER_ERROR;
+            };
+            return ResponseEntity.status(status).body(e.getMessage());
+        }
+    }
+
+}
diff --git a/src/main/java/eu/ztsh/wymiana/web/controller/UserController.java b/src/main/java/eu/ztsh/wymiana/web/controller/UserController.java
index da83862..319d93a 100644
--- a/src/main/java/eu/ztsh/wymiana/web/controller/UserController.java
+++ b/src/main/java/eu/ztsh/wymiana/web/controller/UserController.java
@@ -6,6 +6,7 @@ import eu.ztsh.wymiana.service.UserService;
 import eu.ztsh.wymiana.validation.ValidationFailedException;
 import eu.ztsh.wymiana.web.model.UserCreateRequest;
 import jakarta.validation.Valid;
+import jakarta.validation.ValidationException;
 import lombok.RequiredArgsConstructor;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -27,7 +28,13 @@ public class UserController {
 
     @GetMapping("{pesel}")
     public ResponseEntity<User> get(@PathVariable("pesel") String pesel) {
-        return ResponseEntity.of(userService.get(pesel));
+        try {
+            return userService.get(pesel)
+                .map(ResponseEntity::ok)
+                .orElse(ResponseEntity.notFound().build());
+        } catch (ValidationException e) {
+            return ResponseEntity.badRequest().build();
+        }
     }
 
     @PostMapping
diff --git a/src/test/java/eu/ztsh/wymiana/EntityCreator.java b/src/test/java/eu/ztsh/wymiana/EntityCreator.java
index 5cb9498..617cbfa 100644
--- a/src/test/java/eu/ztsh/wymiana/EntityCreator.java
+++ b/src/test/java/eu/ztsh/wymiana/EntityCreator.java
@@ -48,7 +48,7 @@ public class EntityCreator {
             currencies.put("PLN", new Currency("PLN", pln));
         }
         if (usd > 0) {
-            currencies.put("USD", new Currency("USD", pln));
+            currencies.put("USD", new Currency("USD", usd));
         }
         return new User(Constants.NAME, Constants.SURNAME, Constants.PESEL, currencies);
     }
diff --git a/src/test/java/eu/ztsh/wymiana/service/CurrencyServiceTest.java b/src/test/java/eu/ztsh/wymiana/service/CurrencyServiceTest.java
index 9603e00..c44625e 100644
--- a/src/test/java/eu/ztsh/wymiana/service/CurrencyServiceTest.java
+++ b/src/test/java/eu/ztsh/wymiana/service/CurrencyServiceTest.java
@@ -5,6 +5,7 @@ import eu.ztsh.wymiana.RepositoryBasedTest;
 import eu.ztsh.wymiana.data.repository.UserRepository;
 import eu.ztsh.wymiana.exception.ExchangeFailedException;
 import eu.ztsh.wymiana.exception.InsufficientFundsException;
+import eu.ztsh.wymiana.exception.UserNotFoundException;
 import eu.ztsh.wymiana.validation.InstanceValidator;
 import eu.ztsh.wymiana.validation.ValidationFailedException;
 import jakarta.transaction.Transactional;
@@ -175,7 +176,7 @@ class CurrencyServiceTest extends RepositoryBasedTest {
             .toSell(USD_SELL)
             .build();
         assertThatThrownBy(() -> currencyService.exchange(entity))
-            .isInstanceOf(ExchangeFailedException.class);
+            .isInstanceOf(UserNotFoundException.class);
     }
 
     @Test
diff --git a/src/test/java/eu/ztsh/wymiana/web/ApplicationIntegrationTests.java b/src/test/java/eu/ztsh/wymiana/web/ApplicationIntegrationTests.java
index 38fdfae..816cc99 100644
--- a/src/test/java/eu/ztsh/wymiana/web/ApplicationIntegrationTests.java
+++ b/src/test/java/eu/ztsh/wymiana/web/ApplicationIntegrationTests.java
@@ -4,7 +4,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import eu.ztsh.wymiana.EntityCreator;
 import eu.ztsh.wymiana.WireMockExtension;
-import eu.ztsh.wymiana.model.User;
 import eu.ztsh.wymiana.util.UserMapper;
 import org.junit.jupiter.api.ClassOrderer;
 import org.junit.jupiter.api.DisplayName;
@@ -83,7 +82,7 @@ class ApplicationIntegrationTests {
                 .uri(endpoint)
                 .bodyValue(EntityCreator.userRequest().pln(100).build())
                 .exchange()
-                .expectStatus().is2xxSuccessful();
+                .expectStatus().isNoContent();
         }
 
         @Test
@@ -94,7 +93,7 @@ class ApplicationIntegrationTests {
                 .bodyValue(EntityCreator.userRequest().pesel(INVALID_PESEL).build())
                 .exchange()
                 .expectStatus()
-                .is4xxClientError();
+                .isBadRequest();
         }
 
         @Test
@@ -104,7 +103,7 @@ class ApplicationIntegrationTests {
                 .uri(endpoint)
                 .bodyValue(EntityCreator.userRequest().build())
                 .exchange()
-                .expectStatus().is4xxClientError()
+                .expectStatus().isEqualTo(409)
                 .expectBody(String.class).isEqualTo("User with PESEL %s already exists".formatted(PESEL));
         }
 
@@ -114,7 +113,7 @@ class ApplicationIntegrationTests {
             webTestClient.get()
                 .uri(endpoint.concat("/").concat(PESEL))
                 .exchange()
-                .expectStatus().is2xxSuccessful()
+                .expectStatus().isOk()
                 .expectBody().json(asJson(UserMapper.entityToPojo(EntityCreator.userEntity().pln(100).build())));
         }
 
@@ -124,7 +123,7 @@ class ApplicationIntegrationTests {
             webTestClient.get()
                 .uri(endpoint.concat("/").concat(ANOTHER_PESEL))
                 .exchange()
-                .expectStatus().is4xxClientError();
+                .expectStatus().isNotFound();
         }
 
         @Test
@@ -133,7 +132,7 @@ class ApplicationIntegrationTests {
             webTestClient.get()
                 .uri(endpoint.concat("/").concat(INVALID_PESEL))
                 .exchange()
-                .expectStatus().is4xxClientError();
+                .expectStatus().isBadRequest();
         }
 
     }
@@ -158,18 +157,19 @@ class ApplicationIntegrationTests {
                     .toSell(PLN)
                     .build())
                 .exchange()
-                .expectStatus().is5xxServerError();
+                .expectStatus().isEqualTo(500);
         }
 
         @Test
         @DisplayName("03.2: Perform valid money exchange")
-        void exchangeTest() throws JsonProcessingException {
+        void exchangeTest() {
             var date = getTodayOrLastFriday();
             WireMockExtension.response(
                 URI_PATTERN.formatted(date),
                 200,
-                new ObjectMapper().writeValueAsString(EntityCreator.rates(date))
+                asJson(EntityCreator.rates(date))
             );
+            var expected = asJson(EntityCreator.user(100 - PLN, USD_BUY));
             webTestClient.post()
                 .uri(endpoint)
                 .bodyValue(EntityCreator.exchangeRequest()
@@ -178,8 +178,9 @@ class ApplicationIntegrationTests {
                     .toSell(PLN)
                     .build())
                 .exchange()
-                .expectStatus().is2xxSuccessful()
-                .expectBody(User.class).isEqualTo(EntityCreator.user(100 - PLN, USD_BUY));
+                .expectStatus().isOk()
+                .expectBody().json(expected);
+            WireMockExtension.verifyGet(2, URI_PATTERN.formatted(date));
         }
 
         @Test
@@ -194,8 +195,8 @@ class ApplicationIntegrationTests {
                     .toSell(PLN)
                     .build())
                 .exchange()
-                .expectStatus().is4xxClientError()
-                .expectBody(String.class).isEqualTo("An exchange error has occurred");
+                .expectStatus().isNotFound()
+                .expectBody(String.class).isEqualTo("User with PESEL %s not found".formatted(ANOTHER_PESEL));
         }
 
         @Test
@@ -210,7 +211,7 @@ class ApplicationIntegrationTests {
                     .toSell(PLN)
                     .build())
                 .exchange()
-                .expectStatus().is4xxClientError();
+                .expectStatus().isBadRequest();
         }
 
         @Test
@@ -219,13 +220,12 @@ class ApplicationIntegrationTests {
             webTestClient.post()
                 .uri(endpoint)
                 .bodyValue(EntityCreator.exchangeRequest()
-                    .pesel(ANOTHER_PESEL)
                     .from(USD_SYMBOL)
                     .to(PLN_SYMBOL)
                     .toBuy(PLN)
                     .build())
                 .exchange()
-                .expectStatus().is4xxClientError();
+                .expectStatus().isBadRequest();
         }
 
         private String getTodayOrLastFriday() {