diff --git a/BinDays.Api.Collectors/Collectors/Councils/Mansfield.cs b/BinDays.Api.Collectors/Collectors/Councils/Mansfield.cs
new file mode 100644
index 00000000..155e98d9
--- /dev/null
+++ b/BinDays.Api.Collectors/Collectors/Councils/Mansfield.cs
@@ -0,0 +1,241 @@
+namespace BinDays.Api.Collectors.Collectors.Councils;
+
+using BinDays.Api.Collectors.Collectors.Vendors;
+using BinDays.Api.Collectors.Models;
+using BinDays.Api.Collectors.Utilities;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text.Json;
+using System.Text.RegularExpressions;
+
+///
+/// Collector implementation for Mansfield.
+///
+internal sealed partial class Mansfield : GovUkCollectorBase, ICollector
+{
+ ///
+ public string Name => "Mansfield";
+
+ ///
+ public Uri WebsiteUrl => new("https://www.mansfield.gov.uk/");
+
+ ///
+ public override string GovUkId => "mansfield";
+
+ ///
+ /// The list of bin types for this collector.
+ ///
+ private readonly IReadOnlyCollection _binTypes = [
+ new()
+ {
+ Name = "General Waste",
+ Colour = BinColour.Green,
+ Keys = [ "General Waste Collection Service" ],
+ },
+ new()
+ {
+ Name = "Recycling",
+ Colour = BinColour.Blue,
+ Keys = [ "Recycling Waste Collection Service" ],
+ },
+ new()
+ {
+ Name = "Garden Waste",
+ Colour = BinColour.Brown,
+ Keys = [ "Garden Waste Collection Service" ],
+ },
+ new()
+ {
+ Name = "Glass",
+ Colour = BinColour.Black,
+ Keys = [ "Glass Waste Collection Service" ],
+ },
+ ];
+
+ ///
+ /// The form URL for the collector.
+ ///
+ private const string _formUrl = "https://www.mansfield.gov.uk/xfp/form/1339";
+
+ ///
+ /// Regex for the token from the form.
+ ///
+ [GeneratedRegex(@"name=""__token"" value=""(?[^""]+)""")]
+ private static partial Regex TokenRegex();
+
+ ///
+ /// Regex for the addresses from the data.
+ ///
+ [GeneratedRegex(@"")]
+ private static partial Regex AddressRegex();
+
+ ///
+ public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? clientSideResponse)
+ {
+ // Prepare client-side request for getting token
+ if (clientSideResponse == null)
+ {
+ var clientSideRequest = new ClientSideRequest
+ {
+ RequestId = 1,
+ Url = _formUrl,
+ Method = "GET",
+ Headers = new() {
+ {"user-agent", Constants.UserAgent},
+ },
+ };
+
+ var getAddressesResponse = new GetAddressesResponse
+ {
+ NextClientSideRequest = clientSideRequest,
+ };
+
+ return getAddressesResponse;
+ }
+ // Prepare client-side request for getting addresses
+ else if (clientSideResponse.RequestId == 1)
+ {
+ var token = TokenRegex().Match(clientSideResponse.Content).Groups["token"].Value;
+ var setCookieHeader = clientSideResponse.Headers["set-cookie"]!;
+ var requestCookies = ProcessingUtilities.ParseSetCookieHeaderForRequestCookie(setCookieHeader);
+
+ var requestBody = ProcessingUtilities.ConvertDictionaryToFormData(new()
+ {
+ {"__token", token},
+ {"page", "2615"},
+ {"locale", "en_GB"},
+ {"injectedParams", "{\"formID\":\"1339\"}"},
+ {"q3fc8e993e4e89b244317c1f13b6d65c0b0ef1ad2_0_0", postcode},
+ {"callback", "{\"action\":\"ic\",\"element\":\"q3fc8e993e4e89b244317c1f13b6d65c0b0ef1ad2\",\"data\":0,\"tableRow\":-1}"},
+ {"q177fee160e3d7694451f7d047342e9c0e3ce01c9", string.Empty},
+ });
+
+ var clientSideRequest = new ClientSideRequest
+ {
+ RequestId = 2,
+ Url = _formUrl,
+ Method = "POST",
+ Headers = new() {
+ {"user-agent", Constants.UserAgent},
+ {"content-type", "application/x-www-form-urlencoded"},
+ {"cookie", requestCookies},
+ },
+ Body = requestBody,
+ };
+
+ var getAddressesResponse = new GetAddressesResponse
+ {
+ NextClientSideRequest = clientSideRequest,
+ };
+
+ return getAddressesResponse;
+ }
+ // Process addresses from response
+ else if (clientSideResponse.RequestId == 2)
+ {
+ var rawAddresses = AddressRegex().Matches(clientSideResponse.Content)!;
+
+ // Iterate through each address, and create a new address object
+ var addresses = new List();
+ foreach (Match rawAddress in rawAddresses)
+ {
+ var uid = rawAddress.Groups["uid"].Value;
+
+ if (string.IsNullOrWhiteSpace(uid) || uid == "0")
+ {
+ continue;
+ }
+
+ var address = new Address
+ {
+ Property = rawAddress.Groups["address"].Value.Trim(),
+ Postcode = postcode,
+ Uid = uid,
+ };
+
+ addresses.Add(address);
+ }
+
+ var getAddressesResponse = new GetAddressesResponse
+ {
+ Addresses = [.. addresses],
+ };
+
+ return getAddressesResponse;
+ }
+
+ throw new InvalidOperationException("Invalid client-side request.");
+ }
+
+ ///
+ public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? clientSideResponse)
+ {
+ // Prepare client-side request for getting bin days
+ if (clientSideResponse == null)
+ {
+ var fromDate = DateOnly.FromDateTime(DateTime.Now);
+ var toDate = fromDate.AddDays(364);
+
+ var requestUrl = $"https://portal.mansfield.gov.uk/mdcwhitespacewebservice/WhiteSpaceWS.asmx/GetCollectionByUPRNAndDatePlus?&apiKey=mDc-wN3-B0f-f4P&UPRN={address.Uid}&ColFromDate={fromDate:yyyy-MM-dd}&ColToDate={toDate:yyyy-MM-dd}";
+
+ var clientSideRequest = new ClientSideRequest
+ {
+ RequestId = 1,
+ Url = requestUrl,
+ Method = "GET",
+ Headers = new() {
+ {"user-agent", Constants.UserAgent},
+ },
+ };
+
+ var getBinDaysResponse = new GetBinDaysResponse
+ {
+ NextClientSideRequest = clientSideRequest,
+ };
+
+ return getBinDaysResponse;
+ }
+ // Process bin days from response
+ else if (clientSideResponse.RequestId == 1)
+ {
+ using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content);
+ var collections = jsonDoc.RootElement.GetProperty("Collections");
+
+ // Iterate through each bin day, and create a new bin day object
+ var binDays = new List();
+ foreach (var collection in collections.EnumerateArray())
+ {
+ var service = collection.GetProperty("Service").GetString()!;
+ var dateString = collection.GetProperty("Date").GetString()!;
+
+ var collectionDate = DateTime.ParseExact(
+ dateString,
+ "dd/MM/yyyy HH:mm:ss",
+ CultureInfo.InvariantCulture,
+ DateTimeStyles.None
+ );
+
+ var matchedBinTypes = ProcessingUtilities.GetMatchingBins(_binTypes, service);
+
+ var binDay = new BinDay
+ {
+ Date = DateOnly.FromDateTime(collectionDate),
+ Address = address,
+ Bins = matchedBinTypes,
+ };
+
+ binDays.Add(binDay);
+ }
+
+ var getBinDaysResponse = new GetBinDaysResponse
+ {
+ BinDays = ProcessingUtilities.ProcessBinDays(binDays),
+ };
+
+ return getBinDaysResponse;
+ }
+
+ throw new InvalidOperationException("Invalid client-side request.");
+ }
+}
diff --git a/BinDays.Api.IntegrationTests/Collectors/Councils/MansfieldTests.cs b/BinDays.Api.IntegrationTests/Collectors/Councils/MansfieldTests.cs
new file mode 100644
index 00000000..e78b51dc
--- /dev/null
+++ b/BinDays.Api.IntegrationTests/Collectors/Councils/MansfieldTests.cs
@@ -0,0 +1,36 @@
+namespace BinDays.Api.IntegrationTests.Collectors.Councils;
+
+using BinDays.Api.Collectors.Collectors;
+using BinDays.Api.Collectors.Collectors.Councils;
+using BinDays.Api.Collectors.Services;
+using BinDays.Api.IntegrationTests.Helpers;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+public class MansfieldTests
+{
+ private readonly IntegrationTestClient _client;
+ private static readonly ICollector _collector = new Mansfield();
+ private readonly CollectorService _collectorService = new([_collector]);
+ private readonly ITestOutputHelper _outputHelper;
+
+ public MansfieldTests(ITestOutputHelper outputHelper)
+ {
+ _outputHelper = outputHelper;
+ _client = new IntegrationTestClient(outputHelper);
+ }
+
+ [Theory]
+ [InlineData("NG19 8PL")]
+ public async Task GetBinDaysTest(string postcode)
+ {
+ await TestSteps.EndToEnd(
+ _client,
+ _collectorService,
+ _collector,
+ postcode,
+ _outputHelper
+ );
+ }
+}