diff --git a/config/schema/commerce_datatrans.schema.yml b/config/schema/commerce_datatrans.schema.yml
index ee9b224..c332678 100644
--- a/config/schema/commerce_datatrans.schema.yml
+++ b/config/schema/commerce_datatrans.schema.yml
@@ -31,3 +31,6 @@ commerce_payment.commerce_payment_gateway.plugin.datatrans:
     hmac_key_2:
       type: string
       label: 'HMAC 2 key'
+    password:
+      type: string
+      label: 'Password'
diff --git a/src/Plugin/Commerce/PaymentGateway/Datatrans.php b/src/Plugin/Commerce/PaymentGateway/Datatrans.php
index 41b3800..4d26b45 100644
--- a/src/Plugin/Commerce/PaymentGateway/Datatrans.php
+++ b/src/Plugin/Commerce/PaymentGateway/Datatrans.php
@@ -12,11 +12,17 @@ use Drupal\commerce_payment\Exception\PaymentGatewayException;
 use Drupal\commerce_payment\PaymentMethodTypeManager;
 use Drupal\commerce_payment\PaymentTypeManager;
 use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OffsitePaymentGatewayBase;
+use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\SupportsRefundsInterface;
+use Drupal\commerce_price\Price;
 use Drupal\Component\Datetime\TimeInterface;
+use Drupal\Component\Serialization\Json;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
+use Drupal\Core\Render\Markup;
 use Drupal\Core\Url;
+use GuzzleHttp\ClientInterface;
+use GuzzleHttp\Exception\ClientException;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
@@ -40,7 +46,7 @@ use Symfony\Component\HttpFoundation\Response;
  *   },
  * )
  */
-class Datatrans extends OffsitePaymentGatewayBase {
+class Datatrans extends OffsitePaymentGatewayBase implements SupportsRefundsInterface {
 
   /**
    * Logger.
@@ -49,6 +55,13 @@ class Datatrans extends OffsitePaymentGatewayBase {
    */
   protected $logger;
 
+  /**
+   * The HTTP client.
+   *
+   * @var \GuzzleHttp\ClientInterface
+   */
+  protected $httpClient;
+
   /**
    * Constructs a Datatrans object.
    *
@@ -69,9 +82,10 @@ class Datatrans extends OffsitePaymentGatewayBase {
    * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
    *   The logger factory service.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, LoggerChannelFactoryInterface $logger_factory) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, LoggerChannelFactoryInterface $logger_factory, ClientInterface $http_client) {
     parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $payment_type_manager, $payment_method_type_manager, $time);
     $this->logger = $logger_factory->get('commerce_datatrans');
+    $this->httpClient = $http_client;
   }
 
   /**
@@ -86,7 +100,8 @@ class Datatrans extends OffsitePaymentGatewayBase {
       $container->get('plugin.manager.commerce_payment_type'),
       $container->get('plugin.manager.commerce_payment_method_type'),
       $container->get('datetime.time'),
-      $container->get('logger.factory')
+      $container->get('logger.factory'),
+      $container->get('http_client')
     );
   }
 
@@ -96,7 +111,7 @@ class Datatrans extends OffsitePaymentGatewayBase {
   public function defaultConfiguration() {
     return [
         'merchant_id' => '',
-        'service_url' => ' https://pilot.datatrans.biz/upp/jsp/upStart.jsp',
+        'service_url' => 'https://pay.sandbox.datatrans.com/upp/jsp/upStart.jsp',
         'req_type' => 'CAA',
         'use_alias' => FALSE,
         'security_level' => 2,
@@ -104,6 +119,7 @@ class Datatrans extends OffsitePaymentGatewayBase {
         'hmac_key' => '',
         'use_hmac_2' => FALSE,
         'hmac_key_2' => '',
+        'password' => '',
     ] + parent::defaultConfiguration();
   }
 
@@ -172,7 +188,7 @@ class Datatrans extends OffsitePaymentGatewayBase {
       '#description' => t('Used for security level 1'),
       '#states' => [
         'visible' => [
-          ':input[name="configuration[security][security_level]"]' => ['value' => '1'],
+          ':input[name="configuration[datatrans][security][security_level]"]' => ['value' => '1'],
         ],
       ],
     ];
@@ -184,7 +200,7 @@ class Datatrans extends OffsitePaymentGatewayBase {
       '#description' => t('Used for security level 2'),
       '#states' => [
         'visible' => [
-          ':input[name="configuration[security][security_level]"]' => ['value' => '2'],
+          ':input[name="configuration[datatrans][security][security_level]"]' => ['value' => '2'],
         ],
       ],
     ];
@@ -195,7 +211,7 @@ class Datatrans extends OffsitePaymentGatewayBase {
       '#default_value' => $this->configuration['use_hmac_2'],
       '#states' => array(
         'visible' => array(
-          ':input[name="configuration[security][security_level]"]' => ['value' => '2'],
+          ':input[name="configuration[datatrans][security][security_level]"]' => ['value' => '2'],
         ),
       ),
     );
@@ -206,11 +222,18 @@ class Datatrans extends OffsitePaymentGatewayBase {
       '#default_value' => $this->configuration['hmac_key_2'],
       '#states' => array(
         'visible' => array(
-          ':input[name="configuration[security][security_level]"]' => ['value' => '2'],
+          ':input[name="configuration[datatrans][security][security_level]"]' => ['value' => '2'],
         ),
       ),
     );
 
+    $form['security']['password'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('Password'),
+      '#description' => $this->t('Required for Server to server API requests like refund.'),
+      '#default_value' => $this->configuration['password'],
+    );
+
     return $form;
   }
 
@@ -230,6 +253,7 @@ class Datatrans extends OffsitePaymentGatewayBase {
       $this->configuration['hmac_key'] = $values['security']['hmac_key'];
       $this->configuration['use_hmac_2'] = $values['security']['use_hmac_2'];
       $this->configuration['hmac_key_2'] = $values['security']['hmac_key_2'];
+      $this->configuration['password'] = $values['security']['password'];
     }
   }
 
@@ -455,4 +479,71 @@ class Datatrans extends OffsitePaymentGatewayBase {
     $payment->save();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function refundPayment(PaymentInterface $payment, Price $amount = NULL) {
+    $this->assertPaymentState($payment, ['completed', 'partially_refunded']);
+    // If not specified, refund the entire amount.
+    $amount = $amount ?: $payment->getAmount();
+    $this->assertRefundAmount($payment, $amount);
+
+    $data = [
+      'amount' => $this->toMinorUnits($amount),
+      'currency' => $amount->getCurrencyCode(),
+      'refno' => $payment->getOrderId(),
+    ];
+
+    $hostname = parse_url($this->configuration['service_url'], PHP_URL_HOST);
+    // @todo: Add an explicit setting for this?
+    $hostname = \str_replace('pay.', 'api.', $hostname);
+    if (empty($hostname) || empty($this->configuration['password'])) {
+      throw new PaymentGatewayException($this->t('Invalid configuration, ensure that there is a valid URL and password.'));
+    }
+    $url = 'https://' . $hostname . '/v1/transactions/' . $payment->getRemoteId() . '/credit';
+
+    $options = [
+      'allow_redirects' => FALSE,
+      'auth' => [$this->configuration['merchant_id'], $this->configuration['password']],
+      'json' => $data,
+      'headers' => [
+        'Content-Type' => 'application/json'
+      ]
+    ];
+
+    try {
+      $response = $this->httpClient->request('POST', $url, $options);
+    }
+    catch (ClientException $e) {
+
+      $response = $e->getResponse();
+      $body = Json::decode((string) $response->getBody());
+
+      $arguments = [
+        '@code' => $body['error']['code'],
+        '@error' => $body['error']['message'],
+      ];
+      throw new PaymentGatewayException($this->t('Refund failed with code @code: @error', $arguments), 0, $e);
+    }
+    catch (\Exception $e) {
+      throw new PaymentGatewayException($this->t('Refund failed: @error.', ['@error' => $e->getMessage()]), 0, $e);
+    }
+
+    if ($response->getStatusCode() != 200) {
+      throw new PaymentGatewayException($this->t('Refund failed with unexpected response: @response', ['@response' => (string) $response->getBody()]));
+    }
+
+    $old_refunded_amount = $payment->getRefundedAmount();
+    $new_refunded_amount = $old_refunded_amount->add($amount);
+    if ($new_refunded_amount->lessThan($payment->getAmount())) {
+      $payment->state = 'partially_refunded';
+    }
+    else {
+      $payment->state = 'refunded';
+    }
+
+    $payment->setRefundedAmount($new_refunded_amount);
+    $payment->save();
+  }
+
 }
diff --git a/tests/src/Kernel/DatatransKernelTest.php b/tests/src/Kernel/DatatransKernelTest.php
index 6a40d5c..833c648 100644
--- a/tests/src/Kernel/DatatransKernelTest.php
+++ b/tests/src/Kernel/DatatransKernelTest.php
@@ -3,9 +3,13 @@
 namespace Drupal\Tests\commerce_datatrans\Kernel;
 
 use Drupal\commerce_order\Entity\OrderItemType;
+use Drupal\commerce_payment\Entity\Payment;
 use Drupal\commerce_payment\Entity\PaymentGateway;
+use Drupal\commerce_price\Price;
 use Drupal\Tests\commerce\Kernel\CommerceKernelTestBase;
 use Drupal\commerce_datatrans\Plugin\Commerce\PaymentGateway\Datatrans;
+use GuzzleHttp\ClientInterface;
+use GuzzleHttp\Psr7\Response;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -29,6 +33,13 @@ class DatatransKernelTest extends CommerceKernelTestBase {
    */
   protected $order;
 
+  /**
+   * The payment gateway config entity.
+   *
+   * @var \Drupal\commerce_payment\Entity\PaymentGatewayInterface
+   */
+  protected $paymentGateway;
+
   public static $modules = [
     'entity_reference_revisions',
     'state_machine',
@@ -77,6 +88,12 @@ class DatatransKernelTest extends CommerceKernelTestBase {
     $order_item->save();
     $this->order->setItems([$order_item]);
     $this->order->save();
+
+    $this->paymentGateway = PaymentGateway::create([
+      'id' => 'datatrans_id',
+      'plugin' => 'datatrans',
+    ]);
+    $this->paymentGateway->save();
   }
 
   /**
@@ -85,17 +102,7 @@ class DatatransKernelTest extends CommerceKernelTestBase {
    * @covers ::processPayment
    */
   public function testOnReturnComplete() {
-    // Initialize the datatrans gateway.
-    $payment_gateway = PaymentGateway::create([
-      'id' => 'datatrans_id',
-      'plugin' => 'datatrans',
-    ]);
-    $payment_gateway->save();
-    $configuration = [
-      '_entity' => $payment_gateway,
-    ];
-    $gateway_plugin_manager = $this->container->get('plugin.manager.commerce_payment_gateway');
-    $datatrans = new Datatrans($configuration, 'datatrans', $gateway_plugin_manager->getDefinition('datatrans'), $this->entityTypeManager, $this->container->get('plugin.manager.commerce_payment_type'), $this->container->get('plugin.manager.commerce_payment_method_type'), $this->container->get('datetime.time'), $this->container->get('logger.factory'));
+    $datatrans = $this->getDatatransGateway();
 
     // Create the request and call onReturn().
     $request = Request::create('', 'POST');
@@ -135,16 +142,7 @@ class DatatransKernelTest extends CommerceKernelTestBase {
    */
   public function testOnReturnAuthorizeOnly() {
     // Initialize the datatrans gateway.
-    $payment_gateway = PaymentGateway::create([
-      'id' => 'datatrans_id',
-      'plugin' => 'datatrans',
-    ]);
-    $payment_gateway->save();
-    $configuration = [
-      '_entity' => $payment_gateway,
-    ];
-    $gateway_plugin_manager = $this->container->get('plugin.manager.commerce_payment_gateway');
-    $datatrans = new Datatrans($configuration, 'datatrans', $gateway_plugin_manager->getDefinition('datatrans'), $this->entityTypeManager, $this->container->get('plugin.manager.commerce_payment_type'), $this->container->get('plugin.manager.commerce_payment_method_type'), $this->container->get('datetime.time'), $this->container->get('logger.factory'));
+    $datatrans = $this->getDatatransGateway();
 
     // Create the request and call onReturn().
     $request = Request::create('', 'POST');
@@ -174,4 +172,100 @@ class DatatransKernelTest extends CommerceKernelTestBase {
     $this->assertEquals('datatrans_id', $payment->getPaymentGatewayId());
   }
 
+  /**
+   * @covers ::refundPayment
+   */
+  public function testRefundPayment() {
+
+    $http_client = $this->prophesize(ClientInterface::class);
+    $expected_options = [
+      'allow_redirects' => FALSE,
+      'auth' => ['', 'secret'],
+      'json' => ['amount' => 99900, 'currency' => 'USD', 'refno' => '1'],
+      'headers' => ['Content-Type' => 'application/json'],
+    ];
+    $http_client->request('POST', 'https://api.sandbox.datatrans.com/v1/transactions/123/credit', $expected_options)->willReturn(new Response());
+    $this->container->set('http_client', $http_client->reveal());
+
+    $datatrans = $this->getDatatransGateway();
+
+    /** @var \Drupal\commerce_payment\Entity\PaymentInterface $payment */
+    $payment = Payment::create([
+      'state' => 'completed',
+      'amount' => $this->order->getTotalPrice(),
+      'payment_gateway' => $this->paymentGateway->id(),
+      'order_id' => $this->order->id(),
+      'test' => TRUE,
+      'remote_id' => '123',
+      'remote_state' => 'test',
+      'authorized' => \Drupal::time()->getRequestTime(),
+    ]);
+    $payment->save();
+
+    $datatrans->refundPayment($payment);
+
+    $this->assertEquals('refunded', $payment->getState()->value);
+    $this->assertEquals(123, $payment->getRemoteId());
+    $this->assertEquals($this->order->getTotalPrice(), $payment->getAmount());
+    $this->assertEquals($this->order->getTotalPrice(), $payment->getRefundedAmount());
+    $this->assertEquals(new Price(0, 'USD'), $payment->getBalance());
+    $this->assertEquals('datatrans_id', $payment->getPaymentGatewayId());
+  }
+
+  /**
+   * @covers ::refundPayment
+   */
+  public function testRefundPaymentPartial() {
+
+    $http_client = $this->prophesize(ClientInterface::class);
+    $expected_options = [
+      'allow_redirects' => FALSE,
+      'auth' => ['', 'secret'],
+      'json' => ['amount' => 12350, 'currency' => 'USD', 'refno' => '1'],
+      'headers' => ['Content-Type' => 'application/json'],
+    ];
+    $http_client->request('POST', 'https://api.sandbox.datatrans.com/v1/transactions/123/credit', $expected_options)->willReturn(new Response());
+    $this->container->set('http_client', $http_client->reveal());
+
+    $datatrans = $this->getDatatransGateway();
+
+    /** @var \Drupal\commerce_payment\Entity\PaymentInterface $payment */
+    $payment = Payment::create([
+      'state' => 'completed',
+      'amount' => $this->order->getTotalPrice(),
+      'payment_gateway' => $this->paymentGateway->id(),
+      'order_id' => $this->order->id(),
+      'test' => TRUE,
+      'remote_id' => '123',
+      'remote_state' => 'test',
+      'authorized' => \Drupal::time()->getRequestTime(),
+    ]);
+    $payment->save();
+
+    $refund_amount = new Price('123.50', 'USD');
+    $datatrans->refundPayment($payment, $refund_amount);
+
+    $this->assertEquals('partially_refunded', $payment->getState()->value);
+    $this->assertEquals(123, $payment->getRemoteId());
+    $this->assertEquals($this->order->getTotalPrice(), $payment->getAmount());
+    $this->assertEquals($refund_amount, $payment->getRefundedAmount());
+    $this->assertEquals(new Price('875.5', 'USD'), $payment->getBalance());
+    $this->assertEquals('datatrans_id', $payment->getPaymentGatewayId());
+  }
+
+  /**
+   * Returns the datatrans gateway.
+   *
+   * @return \Drupal\commerce_datatrans\Plugin\Commerce\PaymentGateway\Datatrans
+   *   The datatrans gateway.
+   */
+  protected function getDatatransGateway() {
+    $configuration = [
+      '_entity' => $this->paymentGateway,
+      'password' => 'secret',
+    ];
+    $gateway_plugin_manager = $this->container->get('plugin.manager.commerce_payment_gateway');
+    return $gateway_plugin_manager->createInstance('datatrans', $configuration);
+  }
+
 }
