diff --git a/examples/ResponseWithHeaders.md b/examples/ResponseWithHeaders.md
new file mode 100644
index 000000000..92631619b
--- /dev/null
+++ b/examples/ResponseWithHeaders.md
@@ -0,0 +1,58 @@
+```csharp
+using System;
+using System.IO;
+using Microsoft.Extensions.Logging;
+using Serilog;
+using Serilog.Events;
+using Twilio;
+using Twilio.Rest.Api.V2010.Account;
+using Twilio.Types;
+using Twilio.Http;
+using Twilio.Credential;
+
+namespace TwilioTest {
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ TwilioClient.Init(ACCOUNT_SID, AUTH_TOKEN);
+ }
+
+ public static void createWithHeaders()
+ {
+ var record = MessageResource.CreateWithHeaders(
+ from: new PhoneNumber("fromNumber"),
+ body: "Body",
+ to: new PhoneNumber("toNumber")
+ );
+ Console.WriteLine(record);
+ Console.WriteLine(record.Headers);
+ Console.WriteLine(record.Data.Sid);
+ }
+
+ public static void fetchWithHeaders()
+ {
+ var record = MessageResource.FetchWithHeaders(pathSid: "SM123");
+ Console.WriteLine(record);
+ Console.WriteLine(record.Headers);
+ Console.WriteLine(record.Data.Body);
+ }
+
+ public static void updateWithHeaders()
+ {
+ var record = MessageResource.UpdateWithHeaders(pathSid: "SM123", body: "");
+ Console.WriteLine(record);
+ Console.WriteLine(record.Headers);
+ Console.WriteLine(record.Data);
+ }
+
+ public static void deleteWithHeaders()
+ {
+ var record = MessageResource.DeleteWithHeaders(pathSid: "SM123");
+ Console.WriteLine(record);
+ Console.WriteLine(record.Headers);
+ Console.WriteLine(record.Data);
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/src/Twilio/Base/ResourceSetResponse.cs b/src/Twilio/Base/ResourceSetResponse.cs
new file mode 100644
index 000000000..878cc66b8
--- /dev/null
+++ b/src/Twilio/Base/ResourceSetResponse.cs
@@ -0,0 +1,66 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Net;
+
+#if NET35
+using Headers = System.Net.WebHeaderCollection;
+#else
+using Headers = System.Net.Http.Headers.HttpResponseHeaders;
+#endif
+
+namespace Twilio.Base
+{
+ ///
+ /// Wrapper class that contains both the resource set and HTTP response headers.
+ /// Implements IEnumerable to allow direct iteration over records.
+ ///
+ /// The type of the resource
+ public class ResourceSetResponse : IEnumerable where T : Resource
+ {
+ ///
+ /// The resource set containing the records
+ ///
+ public ResourceSet Records { get; }
+
+ ///
+ /// HTTP response headers from the initial request
+ ///
+ public Headers Headers { get; }
+
+ ///
+ /// HTTP status code from the initial request
+ ///
+ public HttpStatusCode StatusCode { get; }
+
+ ///
+ /// Create a new ResourceSetResponse
+ ///
+ /// The resource set containing records
+ /// HTTP response headers
+ /// HTTP status code
+ public ResourceSetResponse(ResourceSet records, Headers headers, HttpStatusCode statusCode)
+ {
+ Records = records;
+ Headers = headers;
+ StatusCode = statusCode;
+ }
+
+ ///
+ /// Get enumerator for iterating over resources
+ ///
+ /// IEnumerator of resources
+ public IEnumerator GetEnumerator()
+ {
+ return Records.GetEnumerator();
+ }
+
+ ///
+ /// Get enumerator for iterating over resources
+ ///
+ /// IEnumerator of resources
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+}
diff --git a/src/Twilio/Base/TwilioResponse.cs b/src/Twilio/Base/TwilioResponse.cs
new file mode 100644
index 000000000..b7227817c
--- /dev/null
+++ b/src/Twilio/Base/TwilioResponse.cs
@@ -0,0 +1,45 @@
+using System.Net;
+
+#if NET35
+using Headers = System.Net.WebHeaderCollection;
+#else
+using Headers = System.Net.Http.Headers.HttpResponseHeaders;
+#endif
+
+namespace Twilio.Base
+{
+ ///
+ /// Wrapper class that contains both the resource and HTTP response headers
+ ///
+ /// The type of the resource
+ public class TwilioResponse
+ {
+ ///
+ /// The resource data
+ ///
+ public T Data { get; }
+
+ ///
+ /// HTTP response headers
+ ///
+ public Headers Headers { get; }
+
+ ///
+ /// HTTP status code
+ ///
+ public HttpStatusCode StatusCode { get; }
+
+ ///
+ /// Create a new TwilioResponse
+ ///
+ /// The resource data
+ /// HTTP response headers
+ /// HTTP status code
+ public TwilioResponse(T data, Headers headers, HttpStatusCode statusCode)
+ {
+ Data = data;
+ Headers = headers;
+ StatusCode = statusCode;
+ }
+ }
+}
diff --git a/test/Twilio.Test/Base/ResourceSetResponseTest.cs b/test/Twilio.Test/Base/ResourceSetResponseTest.cs
new file mode 100644
index 000000000..f7394daf0
--- /dev/null
+++ b/test/Twilio.Test/Base/ResourceSetResponseTest.cs
@@ -0,0 +1,176 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using NUnit.Framework;
+using Twilio.Base;
+
+#if !NET35
+using System.Net.Http;
+#endif
+
+namespace Twilio.Tests.Base
+{
+ [TestFixture]
+ public class ResourceSetResponseTest
+ {
+ // Mock resource class for testing
+ private class MockResource : Resource
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+ }
+
+ // Mock ReadOptions for testing
+ private class MockReadOptions : ReadOptions
+ {
+ }
+
+#if !NET35
+ private ResourceSet CreateMockResourceSet(List records)
+ {
+ // Create a JSON string that Page.FromJson can parse
+ var json = CreatePageJson(records);
+ var page = Page.FromJson("records", json);
+ var options = new MockReadOptions();
+ return new ResourceSet(page, options, null);
+ }
+
+ private string CreatePageJson(List records)
+ {
+ var recordsJson = string.Join(",", records.Select(r =>
+ $"{{\"Id\":\"{r.Id}\",\"Name\":\"{r.Name}\"}}"));
+ return $"{{\"records\":[{recordsJson}],\"page_size\":{records.Count},\"uri\":\"/test\"}}";
+ }
+
+ [Test]
+ public void TestResourceSetResponseProperties()
+ {
+ var records = new List
+ {
+ new MockResource { Id = "1", Name = "First" },
+ new MockResource { Id = "2", Name = "Second" }
+ };
+ var resourceSet = CreateMockResourceSet(records);
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new ResourceSetResponse(resourceSet, headers, statusCode);
+
+ Assert.AreEqual(resourceSet, response.Records);
+ Assert.AreEqual(headers, response.Headers);
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ }
+
+ [Test]
+ public void TestResourceSetResponseEnumeration()
+ {
+ var records = new List
+ {
+ new MockResource { Id = "1", Name = "First" },
+ new MockResource { Id = "2", Name = "Second" },
+ new MockResource { Id = "3", Name = "Third" }
+ };
+ var resourceSet = CreateMockResourceSet(records);
+ resourceSet.AutoPaging = false;
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new ResourceSetResponse(resourceSet, headers, statusCode);
+
+ // Test enumeration through the response
+ var enumeratedRecords = response.ToList();
+ Assert.AreEqual(3, enumeratedRecords.Count);
+ Assert.AreEqual("1", enumeratedRecords[0].Id);
+ Assert.AreEqual("2", enumeratedRecords[1].Id);
+ Assert.AreEqual("3", enumeratedRecords[2].Id);
+ }
+
+ [Test]
+ public void TestResourceSetResponseWithEmptySet()
+ {
+ var records = new List();
+ var resourceSet = CreateMockResourceSet(records);
+ resourceSet.AutoPaging = false;
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new ResourceSetResponse(resourceSet, headers, statusCode);
+
+ var enumeratedRecords = response.ToList();
+ Assert.AreEqual(0, enumeratedRecords.Count);
+ }
+
+ [Test]
+ public void TestResourceSetResponseWithDifferentStatusCodes()
+ {
+ var records = new List
+ {
+ new MockResource { Id = "1", Name = "Test" }
+ };
+ var resourceSet = CreateMockResourceSet(records);
+ var headers = new HttpResponseMessage().Headers;
+
+ var okResponse = new ResourceSetResponse(resourceSet, headers, HttpStatusCode.OK);
+ Assert.AreEqual(HttpStatusCode.OK, okResponse.StatusCode);
+
+ var partialResponse = new ResourceSetResponse(resourceSet, headers, HttpStatusCode.PartialContent);
+ Assert.AreEqual(HttpStatusCode.PartialContent, partialResponse.StatusCode);
+ }
+
+ [Test]
+ public void TestResourceSetResponseForeachEnumeration()
+ {
+ var records = new List
+ {
+ new MockResource { Id = "A", Name = "Alpha" },
+ new MockResource { Id = "B", Name = "Beta" }
+ };
+ var resourceSet = CreateMockResourceSet(records);
+ resourceSet.AutoPaging = false;
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new ResourceSetResponse(resourceSet, headers, statusCode);
+
+ // Test foreach enumeration
+ var ids = new List();
+ foreach (var record in response)
+ {
+ ids.Add(record.Id);
+ }
+
+ Assert.AreEqual(2, ids.Count);
+ Assert.Contains("A", ids);
+ Assert.Contains("B", ids);
+ }
+
+ [Test]
+ public void TestResourceSetResponseLinqOperations()
+ {
+ var records = new List
+ {
+ new MockResource { Id = "1", Name = "Apple" },
+ new MockResource { Id = "2", Name = "Banana" },
+ new MockResource { Id = "3", Name = "Cherry" }
+ };
+ var resourceSet = CreateMockResourceSet(records);
+ resourceSet.AutoPaging = false;
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new ResourceSetResponse(resourceSet, headers, statusCode);
+
+ // Test LINQ operations
+ var firstRecord = response.First();
+ Assert.AreEqual("1", firstRecord.Id);
+
+ var count = response.Count();
+ Assert.AreEqual(3, count);
+
+ var filtered = response.Where(r => r.Name.StartsWith("B")).ToList();
+ Assert.AreEqual(1, filtered.Count);
+ Assert.AreEqual("Banana", filtered[0].Name);
+ }
+#endif
+ }
+}
diff --git a/test/Twilio.Test/Base/TwilioResponseTest.cs b/test/Twilio.Test/Base/TwilioResponseTest.cs
new file mode 100644
index 000000000..7b480f202
--- /dev/null
+++ b/test/Twilio.Test/Base/TwilioResponseTest.cs
@@ -0,0 +1,114 @@
+using System.Net;
+using NUnit.Framework;
+using Twilio.Base;
+
+#if !NET35
+using System.Net.Http;
+#endif
+
+namespace Twilio.Tests.Base
+{
+ [TestFixture]
+ public class TwilioResponseTest
+ {
+ // Mock resource class for testing
+ private class MockResource : Resource
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+ }
+
+#if !NET35
+ [Test]
+ public void TestTwilioResponseWithResource()
+ {
+ var resource = new MockResource { Id = "123", Name = "Test" };
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new TwilioResponse(resource, headers, statusCode);
+
+ Assert.AreEqual(resource, response.Data);
+ Assert.AreEqual(headers, response.Headers);
+ Assert.AreEqual(statusCode, response.StatusCode);
+ }
+
+ [Test]
+ public void TestTwilioResponseWithBool()
+ {
+ var data = true;
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.NoContent;
+
+ var response = new TwilioResponse(data, headers, statusCode);
+
+ Assert.AreEqual(true, response.Data);
+ Assert.AreEqual(headers, response.Headers);
+ Assert.AreEqual(HttpStatusCode.NoContent, response.StatusCode);
+ }
+
+ [Test]
+ public void TestTwilioResponseWithString()
+ {
+ var data = "test string";
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new TwilioResponse(data, headers, statusCode);
+
+ Assert.AreEqual("test string", response.Data);
+ Assert.AreEqual(headers, response.Headers);
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ }
+
+ [Test]
+ public void TestTwilioResponseWithNullData()
+ {
+ MockResource data = null;
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.NotFound;
+
+ var response = new TwilioResponse(data, headers, statusCode);
+
+ Assert.IsNull(response.Data);
+ Assert.AreEqual(headers, response.Headers);
+ Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
+ }
+
+ [Test]
+ public void TestTwilioResponseWithDifferentStatusCodes()
+ {
+ var resource = new MockResource { Id = "456", Name = "Created" };
+ var headers = new HttpResponseMessage().Headers;
+
+ var createdResponse = new TwilioResponse(resource, headers, HttpStatusCode.Created);
+ Assert.AreEqual(HttpStatusCode.Created, createdResponse.StatusCode);
+
+ var acceptedResponse = new TwilioResponse(resource, headers, HttpStatusCode.Accepted);
+ Assert.AreEqual(HttpStatusCode.Accepted, acceptedResponse.StatusCode);
+
+ var badRequestResponse = new TwilioResponse(resource, headers, HttpStatusCode.BadRequest);
+ Assert.AreEqual(HttpStatusCode.BadRequest, badRequestResponse.StatusCode);
+ }
+
+ [Test]
+ public void TestTwilioResponseDataIsReadOnly()
+ {
+ var resource = new MockResource { Id = "789", Name = "ReadOnly" };
+ var headers = new HttpResponseMessage().Headers;
+ var statusCode = HttpStatusCode.OK;
+
+ var response = new TwilioResponse(resource, headers, statusCode);
+
+ // Verify that Data property returns the same instance
+ Assert.AreSame(resource, response.Data);
+
+ // Modify the original resource
+ resource.Name = "Modified";
+
+ // The response should reflect the change since it holds a reference
+ Assert.AreEqual("Modified", response.Data.Name);
+ }
+#endif
+ }
+}