diff --git a/readme.md b/readme.md
index 17b76ccd..aea871d0 100644
--- a/readme.md
+++ b/readme.md
@@ -309,20 +309,21 @@ $connector = new BrowseDataApiConnector(
Not all resources from the Twinfield API are currently implemented. Feel free to create a pull request when you need
support for another resource.
-| Component | get() | listAll() | send() | delete() | Mapper |
-| --------------------------------------------------------------------------------------------------------------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
-| [Articles](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Articles) | :white_check_mark: | | :white_check_mark: | | :white_check_mark: |
-| [BankTransaction](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Transactions/BankTransactions)| | | :white_check_mark: | :white_check_mark: | |
-| [Customer](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Customers) | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
-| [Electronic Bank Statements](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Transactions/BankStatements)| | | :white_check_mark: | | |
-| [Sales Invoices](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/SalesInvoices) | :white_check_mark: | | :white_check_mark: | | :white_check_mark: |
-| [Matching](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Miscellaneous/Matching) | | | :white_check_mark: | | :white_check_mark: | |
-| [Offices](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Offices) | | :white_check_mark: | | | :white_check_mark: |
-| [Suppliers](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Suppliers) | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
+| Component | get() | listAll() | send() | delete() | Mapper |
+|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
+| [Articles](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Articles) | :white_check_mark: | | :white_check_mark: | | :white_check_mark: |
+| [BankTransaction](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Transactions/BankTransactions) | | | :white_check_mark: | :white_check_mark: | |
+| [Currency](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Currencies) | | | :white_check_mark: | | :white_check_mark: |
+| [Customer](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Customers) | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
+| [Electronic Bank Statements](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Transactions/BankStatements) | | | :white_check_mark: | | |
+| [Sales Invoices](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/SalesInvoices) | :white_check_mark: | | :white_check_mark: | | :white_check_mark: |
+| [Matching](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Miscellaneous/Matching) | | | :white_check_mark: | | :white_check_mark: | |
+| [Offices](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Offices) | | :white_check_mark: | | | :white_check_mark: |
+| [Suppliers](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Suppliers) | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
| Transactions:
[Purchase](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/PurchaseTransactions), [Sale](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/SalesTransactions), [Journal](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Transactions/JournalTransactions), [Cash](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Transactions/CashTransactions) | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| [Users](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Users) | | :white_check_mark: | | | |
-| [Vat types](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/VAT) | | :white_check_mark: | | | |
-| [Browse Data](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Request/BrowseData) | :white_check_mark: | | | | :white_check_mark: |
+| [Users](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/Users) | | :white_check_mark: | | | |
+| [Vat types](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Masters/VAT) | | :white_check_mark: | | | |
+| [Browse Data](https://accounting.twinfield.com/webservices/documentation/#/ApiReference/Request/BrowseData) | :white_check_mark: | | | | :white_check_mark: |
## Links
diff --git a/src/ApiConnectors/CurrencyApiConnector.php b/src/ApiConnectors/CurrencyApiConnector.php
new file mode 100644
index 00000000..f8ef310a
--- /dev/null
+++ b/src/ApiConnectors/CurrencyApiConnector.php
@@ -0,0 +1,65 @@
+
+ */
+class CurrencyApiConnector extends BaseApiConnector
+{
+ /**
+ * Sends an Currency instance to Twinfield to update or add.
+ *
+ * @param Currency $currency
+ * @return Currency
+ * @throws Exception
+ */
+ public function send(Currency $currency): Currency
+ {
+ return $this->unwrapSingleResponse($this->sendAll([$currency]));
+ }
+
+ /**
+ * @param Currency[] $currencies
+ * @return MappedResponseCollection
+ * @throws Exception
+ */
+ public function sendAll(array $currencies): MappedResponseCollection
+ {
+ Assert::allIsInstanceOf($currencies, Currency::class);
+
+ /** @var Response[] $responses */
+ $responses = [];
+
+ foreach ($this->getProcessXmlService()->chunk($currencies) as $chunk) {
+
+ $currenciesDocument = new CurrenciesDocument();
+
+ foreach ($chunk as $currency) {
+ $currenciesDocument->addCurrency($currency);
+ }
+
+ $responses[] = $this->sendXmlDocument($currenciesDocument);
+ }
+
+ return $this->getProcessXmlService()->mapAll($responses, "currency", function(Response $response): Currency {
+ return CurrencyMapper::map($response);
+ });
+ }
+}
diff --git a/src/Currency.php b/src/Currency.php
new file mode 100644
index 00000000..f0c32050
--- /dev/null
+++ b/src/Currency.php
@@ -0,0 +1,89 @@
+getOffice()->getCode();
+ }
+
+ public function setOfficeByCode(string $code): self
+ {
+ $office = new Office();
+ $office->setCode($code);
+
+ $this->setOffice( $office );
+ return $this;
+ }
+
+ public function getCode()
+ {
+ return $this->code;
+ }
+
+ public function setCode($code)
+ {
+ $this->code = $code;
+ return $this;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ return $this;
+ }
+
+ public function getShortName()
+ {
+ return $this->shortName;
+ }
+
+ public function setShortName($shortName)
+ {
+ $this->shortName = $shortName;
+ return $this;
+ }
+
+ public function getRates()
+ {
+ return $this->rates;
+ }
+
+ public function addRate(CurrencyRate $rate)
+ {
+ $this->rates[] = $rate;
+ return $this;
+ }
+
+ public function removeRate(CurrencyRate $rate)
+ {
+ $index = array_search($rate, $this->rates);
+
+ if ($index !== false) {
+ unset($this->rates[$index]);
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/CurrencyRate.php b/src/CurrencyRate.php
new file mode 100644
index 00000000..041111b4
--- /dev/null
+++ b/src/CurrencyRate.php
@@ -0,0 +1,47 @@
+status;
+ }
+
+ public function setStatus($status)
+ {
+ $this->status = $status;
+ return $this;
+ }
+
+ public function getStartdate()
+ {
+ return $this->startdate;
+ }
+
+ public function setStartdate($startdate)
+ {
+ $this->startdate = $startdate;
+ return $this;
+ }
+
+ public function getRate()
+ {
+ return $this->rate;
+ }
+
+ public function setRate($rate)
+ {
+ $this->rate = $rate;
+ return $this;
+ }
+}
diff --git a/src/DomDocuments/CurrenciesDocument.php b/src/DomDocuments/CurrenciesDocument.php
new file mode 100644
index 00000000..735cb8ed
--- /dev/null
+++ b/src/DomDocuments/CurrenciesDocument.php
@@ -0,0 +1,121 @@
+
+ */
+class CurrenciesDocument extends \DOMDocument
+{
+ /**
+ * Holds the element
+ * that all additional elements should be a child of
+ * @var \DOMElement
+ */
+ private $currencyElement;
+
+ /**
+ * Creates the element and adds it to the property
+ * currencyElement
+ *
+ * @access public
+ */
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->currencyElement = $this->createElement('currency');
+ $this->appendChild($this->currencyElement);
+ }
+
+ /**
+ * Turns a passed Currency class into the required markup for interacting
+ * with Twinfield.
+ *
+ * This method doesn't return anything, instead just adds the Currency to
+ * this DOMDOcument instance for submission usage.
+ *
+ * @access public
+ * @param Currency $article
+ * @return void | [Adds to this instance]
+ */
+ public function addCurrency(Currency $currency)
+ {
+ // Currency->header elements and their methods
+ $currencyTags = array(
+ 'office' => 'getOfficeCode',
+ 'code' => 'getCode',
+ 'name' => 'getName',
+ 'shortname' => 'getShortName',
+ );
+
+ // Go through each Currency element and use the assigned method
+ foreach ($currencyTags as $tag => $method) {
+ // Make text node for method value
+ $nodeValue = $currency->$method();
+
+ if( ! empty( $nodeValue) ) {
+ $node = $this->createTextNode($nodeValue);
+
+ // Make the actual element and assign the node
+ $element = $this->createElement($tag);
+ $element->appendChild($node);
+
+ // Add the full element
+ $this->currencyElement->appendChild($element);
+ }
+ }
+
+ $rates = $currency->getRates();
+
+ if (!empty($rates)) {
+ // Element tags and their methods for lines
+ $rateTags = [
+ 'startdate' => 'getStartdate',
+ 'rate' => 'getRate'
+ ];
+
+ // Make addresses element
+ $ratesElement = $this->createElement('rates');
+ $this->currencyElement->appendChild($ratesElement);
+
+ // Go through each line assigned to the currency
+ foreach ($rates as $line) {
+ // Makes new currencyLine element
+ $rateElement = $this->createElement('rate');
+ $ratesElement->appendChild($rateElement);
+
+ if( ! empty($line->getStatus() ) ) {
+ $statusElement = $this->createElement($line->getStatus());
+ $element = $this->createElement('status');
+ $element->appendChild($statusElement);
+ $rateElement->appendChild($element);
+ }
+
+ // Go through each line element and use the assigned method
+ foreach ($rateTags as $tag => $method) {
+ // Make the text node for the method value
+ $node = $this->createTextNode($line->$method());
+
+ // Make the actual element and assign the text node
+ $element = $this->createElement($tag);
+ $element->appendChild($node);
+
+ // Add the completed element
+ $rateElement->appendChild($element);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Mappers/CurrencyMapper.php b/src/Mappers/CurrencyMapper.php
new file mode 100644
index 00000000..570fcae8
--- /dev/null
+++ b/src/Mappers/CurrencyMapper.php
@@ -0,0 +1,82 @@
+
+ */
+class CurrencyMapper extends BaseMapper
+{
+
+ /**
+ * Maps a Response object to a clean Currency entity.
+ *
+ * @access public
+ *
+ * @param \PhpTwinfield\Response\Response $response
+ *
+ * @return Currency
+ * @throws \PhpTwinfield\Exception
+ */
+ public static function map(Response $response)
+ {
+ // Generate new Article object
+ $currency = new Currency();
+
+ // Gets the raw DOMDocument response.
+ $responseDOM = $response->getResponseDocument();
+
+ // Article elements and their methods
+ $currencyTags = [
+ 'code' => 'setCode',
+ 'office' => 'setOfficeByCode',
+ 'name' => 'setName',
+ 'shortname' => 'setShortName'
+ ];
+
+ foreach ($currencyTags as $tagName => $tagValue) {
+ $value = $responseDOM->getElementsByTagName($tagName)->item(0)->nodeValue;
+ $method = $currencyTags[$tagName];
+ $currency->$method($value);
+ }
+
+ $ratesDOMTag = $responseDOM->getElementsByTagName('rates');
+
+ if (isset($ratesDOMTag) && $ratesDOMTag->length > 0) {
+ // Element tags and their methods for lines
+ $lineTags = [
+ 'status' => 'setStatus',
+ 'startdate' => 'startdate',
+ 'rate' => 'setRate'
+ ];
+
+ $ratesDOM = $ratesDOMTag->item(0);
+
+ // Loop through each returned line for the article
+ foreach ($ratesDOM->getElementsByTagName('rate') as $rateDom) {
+ if( $rateDom->childElementCount > 0 ) {
+ // Make a new tempory CurrencyRate class
+ $rateLine = new CurrencyRate();
+
+ // Set the attributes ( id,status,inuse)
+ $rateLine->setStartdate($rateDom->getElementsByTagName('startdate')->item(0)->nodeValue)
+ ->setRate($rateDom->getElementsByTagName('rate')->item(0)->nodeValue);
+
+ // Add the bank to the customer
+ $currency->addRate($rateLine);
+
+ // Clean that memory!
+ unset ($rateLine);
+ }
+ }
+ }
+ return $currency;
+ }
+}