From 2d04e21f35b70f4d493a7582ad742570a1dc94c5 Mon Sep 17 00:00:00 2001
From: Cursor Agent <cursoragent@cursor.com>
Date: Wed, 13 May 2026 18:43:37 +0000
Subject: [PATCH 1/5] Add missing AchPayment and AchReceivedPayment fields per
 Unit docs

Per https://docs.unit.co/resources:

AchPayment: add expectedCompletionDate, counterpartyVerificationMethod,
sameDay, secCode.

AchReceivedPayment: add isAdvanceable, direction, originatorEntityId,
receivingEntityName. Also assign self.id which was previously missing.

Co-authored-by: Avery Kushner <avesk@users.noreply.github.com>
---
 unit/models/payment.py | 52 +++++++++++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 13 deletions(-)

diff --git a/unit/models/payment.py b/unit/models/payment.py
index 971b173..12de7ea 100644
--- a/unit/models/payment.py
+++ b/unit/models/payment.py
@@ -23,20 +23,34 @@ class AchPaymentDTO(BasePayment):
     def __init__(self, id: str, created_at: datetime, status: PaymentStatus, counterparty: Counterparty, direction: str,
                  description: str, amount: int, addenda: Optional[str], reason: Optional[str],
                  settlement_date: Optional[datetime], tags: Optional[Dict[str, str]],
-                 relationships: Optional[Dict[str, Relationship]]):
+                 relationships: Optional[Dict[str, Relationship]],
+                 expected_completion_date: Optional[datetime] = None,
+                 counterparty_verification_method: Optional[str] = None,
+                 same_day: Optional[bool] = None, sec_code: Optional[str] = None):
         BasePayment.__init__(self, id, created_at, status, direction, description, amount, reason, tags, relationships)
         self.type = 'achPayment'
         self.attributes["counterparty"] = counterparty
         self.attributes["addenda"] = addenda
+        self.attributes["expectedCompletionDate"] = expected_completion_date
+        self.attributes["counterpartyVerificationMethod"] = counterparty_verification_method
+        self.attributes["sameDay"] = same_day
+        self.attributes["secCode"] = sec_code
         self.settlement_date = settlement_date
 
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
         settlement_date = date_utils.to_date(attributes.get("settlementDate")) if attributes.get("settlementDate") else None
-        return AchPaymentDTO(_id, date_utils.to_datetime(attributes["createdAt"]), attributes["status"],
-                             attributes["counterparty"], attributes["direction"], attributes["description"],
-                             attributes["amount"], attributes.get("addenda"), attributes.get("reason"), settlement_date,
-                             attributes.get("tags"), relationships)
+        expected_completion_date = date_utils.to_date(attributes.get("expectedCompletionDate")) \
+            if attributes.get("expectedCompletionDate") else None
+        return AchPaymentDTO(
+            id=_id, created_at=date_utils.to_datetime(attributes["createdAt"]), status=attributes["status"],
+            counterparty=attributes["counterparty"], direction=attributes["direction"],
+            description=attributes["description"], amount=attributes["amount"], addenda=attributes.get("addenda"),
+            reason=attributes.get("reason"), settlement_date=settlement_date, tags=attributes.get("tags"),
+            relationships=relationships, expected_completion_date=expected_completion_date,
+            counterparty_verification_method=attributes.get("counterpartyVerificationMethod"),
+            same_day=attributes.get("sameDay"), sec_code=attributes.get("secCode"),
+        )
 
 class SimulateIncomingAchPaymentDTO(BasePayment):
     def __init__(self, id: str, created_at: datetime, status: PaymentStatus, direction: str,
@@ -150,11 +164,16 @@ def __init__(self, id: str, created_at: datetime, status: AchReceivedPaymentStat
                  completion_date: datetime, return_reason: Optional[str], amount: int, description: str,
                  addenda: Optional[str], company_name: str, counterparty_routing_number: str, trace_number: str,
                  sec_code: Optional[str], return_cutoff_time: Optional[datetime], can_be_reprocessed: Optional[bool],
-                 tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]]):
+                 tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]],
+                 is_advanceable: Optional[bool] = None, direction: Optional[str] = None,
+                 originator_entity_id: Optional[str] = None, receiving_entity_name: Optional[str] = None):
+        self.id = id
         self.type = "achReceivedPayment"
         self.attributes = {"createdAt": created_at, "status": status, "wasAdvanced": was_advanced,
+                           "isAdvanceable": is_advanceable, "direction": direction,
                            "completionDate": completion_date, "returnReason": return_reason, "description": description,
                            "amount": amount, "addenda": addenda, "companyName": company_name,
+                           "originatorEntityId": originator_entity_id, "receivingEntityName": receiving_entity_name,
                            "counterpartyRoutingNumber": counterparty_routing_number, "traceNumber": trace_number,
                            "secCode": sec_code, "returnCutoffTime": return_cutoff_time, "canBeReprocessed": can_be_reprocessed,
                            "tags": tags}
@@ -162,13 +181,20 @@ def __init__(self, id: str, created_at: datetime, status: AchReceivedPaymentStat
 
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
-        return AchReceivedPaymentDTO(_id, date_utils.to_datetime(attributes["createdAt"]), attributes["status"],
-                                     attributes["wasAdvanced"], attributes["completionDate"],
-                                     attributes.get("returnReason"),attributes["amount"], attributes["description"],
-                                     attributes.get("addenda"), attributes.get("companyName"),
-                                     attributes.get("counterpartyRoutingNumber"), attributes.get("traceNumber"),
-                                     attributes.get("secCode"), attributes.get("returnCutoffTime"), attributes.get("canBeReprocessed"),
-                                     attributes.get("tags"), relationships)
+        return AchReceivedPaymentDTO(
+            id=_id, created_at=date_utils.to_datetime(attributes["createdAt"]), status=attributes["status"],
+            was_advanced=attributes["wasAdvanced"], completion_date=attributes["completionDate"],
+            return_reason=attributes.get("returnReason"), amount=attributes["amount"],
+            description=attributes["description"], addenda=attributes.get("addenda"),
+            company_name=attributes.get("companyName"),
+            counterparty_routing_number=attributes.get("counterpartyRoutingNumber"),
+            trace_number=attributes.get("traceNumber"), sec_code=attributes.get("secCode"),
+            return_cutoff_time=attributes.get("returnCutoffTime"),
+            can_be_reprocessed=attributes.get("canBeReprocessed"), tags=attributes.get("tags"),
+            relationships=relationships, is_advanceable=attributes.get("isAdvanceable"),
+            direction=attributes.get("direction"), originator_entity_id=attributes.get("originatorEntityId"),
+            receiving_entity_name=attributes.get("receivingEntityName"),
+        )
 
 class CreatePaymentBaseRequest(UnitRequest):
     def __init__(self, amount: int, description: str, relationships: Dict[str, Relationship],

From 43b30f64824071e9bdb5ff3a40a66dada5b6cbd5 Mon Sep 17 00:00:00 2001
From: Cursor Agent <cursoragent@cursor.com>
Date: Wed, 13 May 2026 18:43:43 +0000
Subject: [PATCH 2/5] Add missing DepositAccount and AccountEndOfDay fields per
 Unit docs

Per https://docs.unit.co/resources:

DepositAccount: add updatedAt, freezeReason, fraudReason, dacaStatus,
interestTerms.

AccountEndOfDay: add overdraftLimit.

Co-authored-by: Avery Kushner <avesk@users.noreply.github.com>
---
 unit/models/account.py            | 23 ++++++++++++++++-------
 unit/models/account_end_of_day.py | 12 ++++++++----
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/unit/models/account.py b/unit/models/account.py
index 41bf255..d5240a5 100644
--- a/unit/models/account.py
+++ b/unit/models/account.py
@@ -15,22 +15,31 @@ class DepositAccountDTO(object):
     def __init__(self, id: str, created_at: datetime, name: str, deposit_product: str, routing_number: str,
                  account_number: str, currency: str, balance: int, hold: int, available: int, status: AccountStatus,
                  tags: Optional[Dict[str, str]], close_reason: Optional[CloseReason],
-                 relationships: Optional[Dict[str, Relationship]]):
+                 relationships: Optional[Dict[str, Relationship]], updated_at: Optional[datetime] = None,
+                 freeze_reason: Optional[str] = None, fraud_reason: Optional[FraudReason] = None,
+                 daca_status: Optional[str] = None, interest_terms: Optional[Dict] = None):
         self.id = id
         self.type = "depositAccount"
-        self.attributes = {"name": name, "createdAt": created_at, "depositProduct": deposit_product,
+        self.attributes = {"name": name, "createdAt": created_at, "updatedAt": updated_at,
+                           "depositProduct": deposit_product,
                            "routingNumber": routing_number, "accountNumber": account_number, "currency": currency,
                            "balance": balance, "hold": hold, "available": available, "status": status,
-                           "closeReason": close_reason, "tags": tags}
+                           "freezeReason": freeze_reason, "closeReason": close_reason, "fraudReason": fraud_reason,
+                           "dacaStatus": daca_status, "interestTerms": interest_terms, "tags": tags}
         self.relationships = relationships
 
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
         return DepositAccountDTO(
-            _id, date_utils.to_datetime(attributes["createdAt"]), attributes["name"], attributes["depositProduct"],
-            attributes["routingNumber"], attributes["accountNumber"], attributes["currency"], attributes["balance"],
-            attributes["hold"], attributes["available"], attributes["status"], attributes.get("tags"),
-            attributes.get("closeReason"), relationships
+            id=_id, created_at=date_utils.to_datetime(attributes["createdAt"]), name=attributes["name"],
+            deposit_product=attributes["depositProduct"], routing_number=attributes["routingNumber"],
+            account_number=attributes["accountNumber"], currency=attributes["currency"],
+            balance=attributes["balance"], hold=attributes["hold"], available=attributes["available"],
+            status=attributes["status"], tags=attributes.get("tags"),
+            close_reason=attributes.get("closeReason"), relationships=relationships,
+            updated_at=date_utils.to_datetime(attributes.get("updatedAt")) if attributes.get("updatedAt") else None,
+            freeze_reason=attributes.get("freezeReason"), fraud_reason=attributes.get("fraudReason"),
+            daca_status=attributes.get("dacaStatus"), interest_terms=attributes.get("interestTerms"),
         )
 
 
diff --git a/unit/models/account_end_of_day.py b/unit/models/account_end_of_day.py
index b22bf22..e6c5bf6 100644
--- a/unit/models/account_end_of_day.py
+++ b/unit/models/account_end_of_day.py
@@ -5,16 +5,20 @@
 
 class AccountEndOfDayDTO(object):
     def __init__(self, id: str, date: str, balance: int, hold: int, available: int,
-                 relationships: Optional[Dict[str, Relationship]]):
+                 relationships: Optional[Dict[str, Relationship]], overdraft_limit: Optional[int] = None):
         self.id = id
         self.type = "accountEndOfDay"
-        self.attributes = {"date": date, "balance": balance, "hold": hold, "available": available}
+        self.attributes = {"date": date, "balance": balance, "hold": hold, "available": available,
+                           "overdraftLimit": overdraft_limit}
         self.relationships = relationships
 
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
-        return AccountEndOfDayDTO(_id, attributes["date"], attributes["balance"], attributes["hold"],
-                                  attributes["available"], relationships)
+        return AccountEndOfDayDTO(
+            id=_id, date=attributes["date"], balance=attributes["balance"], hold=attributes["hold"],
+            available=attributes["available"], relationships=relationships,
+            overdraft_limit=attributes.get("overdraftLimit"),
+        )
 
 
 class ListAccountEndOfDayParams(UnitParams):

From eebc3e6570648dfb96704ec9cdfa032380964a22 Mon Sep 17 00:00:00 2001
From: Cursor Agent <cursoragent@cursor.com>
Date: Wed, 13 May 2026 18:43:50 +0000
Subject: [PATCH 3/5] Add missing IndividualCustomer and BusinessCustomer
 fields per Unit docs

Per https://docs.unit.co/resources:

IndividualCustomer: add eligibleProducts (Array of Product) and ein
(Optional, sole-prop with EIN).

BusinessCustomer: add eligibleProducts.

Co-authored-by: Avery Kushner <avesk@users.noreply.github.com>
---
 unit/models/customer.py | 46 ++++++++++++++++++++++++++---------------
 1 file changed, 29 insertions(+), 17 deletions(-)

diff --git a/unit/models/customer.py b/unit/models/customer.py
index d1ceab7..c5e0c7a 100644
--- a/unit/models/customer.py
+++ b/unit/models/customer.py
@@ -11,24 +11,31 @@ def __init__(self, id: str, created_at: datetime, full_name: FullName, date_of_b
                  phone: Phone, email: str, ssn: Optional[str], passport: Optional[str], nationality: Optional[str],
                  authorized_users: [AuthorizedUser], tags: Optional[Dict[str, str]],
                  relationships: Optional[Dict[str, Relationship]], status: CustomerStatus,
-                 archive_reason: Optional[ArchiveReason]):
+                 archive_reason: Optional[ArchiveReason], eligible_products: Optional[List[str]] = None,
+                 ein: Optional[str] = None):
         self.id = id
         self.type = 'individualCustomer'
         self.attributes = {"createdAt": created_at, "fullName": full_name, "dateOfBirth": date_of_birth,
                            "address": address, "phone": phone, "email": email, "ssn": ssn, "passport": passport,
-                           "nationality": nationality, "authorizedUsers": authorized_users, "tags": tags,
+                           "nationality": nationality, "ein": ein, "authorizedUsers": authorized_users,
+                           "eligibleProducts": eligible_products, "tags": tags,
                            "status": status, "archiveReason": archive_reason}
         self.relationships = relationships
 
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
         return IndividualCustomerDTO(
-            _id, date_utils.to_datetime(attributes["createdAt"]),
-            FullName.from_json_api(attributes["fullName"]), date_utils.to_date(attributes["dateOfBirth"]),
-            Address.from_json_api(attributes["address"]), Phone.from_json_api(attributes["phone"]),
-            attributes["email"], attributes.get("ssn"), attributes.get("passport"), attributes.get("nationality"),
-            AuthorizedUser.from_json_api(attributes["authorizedUsers"]), attributes.get("tags"), relationships,
-            attributes.get("status"), attributes.get("archiveReason")
+            id=_id, created_at=date_utils.to_datetime(attributes["createdAt"]),
+            full_name=FullName.from_json_api(attributes["fullName"]),
+            date_of_birth=date_utils.to_date(attributes["dateOfBirth"]),
+            address=Address.from_json_api(attributes["address"]),
+            phone=Phone.from_json_api(attributes["phone"]),
+            email=attributes["email"], ssn=attributes.get("ssn"), passport=attributes.get("passport"),
+            nationality=attributes.get("nationality"),
+            authorized_users=AuthorizedUser.from_json_api(attributes["authorizedUsers"]),
+            tags=attributes.get("tags"), relationships=relationships, status=attributes.get("status"),
+            archive_reason=attributes.get("archiveReason"),
+            eligible_products=attributes.get("eligibleProducts"), ein=attributes.get("ein"),
         )
 
 
@@ -37,25 +44,30 @@ def __init__(self, id: str, created_at: datetime, name: str, address: Address, p
                  state_of_incorporation: str, ein: str, entity_type: EntityType, contact: BusinessContact,
                  authorized_users: [AuthorizedUser], dba: Optional[str], tags: Optional[Dict[str, str]],
                  relationships: Optional[Dict[str, Relationship]], status: CustomerStatus,
-                 archive_reason: Optional[ArchiveReason]):
+                 archive_reason: Optional[ArchiveReason], eligible_products: Optional[List[str]] = None):
         self.id = id
         self.type = 'businessCustomer'
         self.attributes = {"createdAt": created_at, "name": name, "address": address, "phone": phone,
                            "stateOfIncorporation": state_of_incorporation, "ein": ein, "entityType": entity_type,
-                           "contact": contact, "authorizedUsers": authorized_users, "dba": dba, "tags": tags,
+                           "contact": contact, "authorizedUsers": authorized_users, "dba": dba,
+                           "eligibleProducts": eligible_products, "tags": tags,
                            "status": status, "archiveReason": archive_reason}
         self.relationships = relationships
 
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
         return BusinessCustomerDTO(
-            _id, date_utils.to_datetime(attributes["createdAt"]), attributes["name"],
-            Address.from_json_api(attributes["address"]), Phone.from_json_api(attributes["phone"]),
-            attributes["stateOfIncorporation"], attributes["ein"], attributes["entityType"],
-            BusinessContact.from_json_api(attributes["contact"]),
-            AuthorizedUser.from_json_api(attributes["authorizedUsers"]),
-            attributes.get("dba"), attributes.get("tags"), relationships, attributes.get("status"),
-            attributes.get("archiveReason"))
+            id=_id, created_at=date_utils.to_datetime(attributes["createdAt"]), name=attributes["name"],
+            address=Address.from_json_api(attributes["address"]),
+            phone=Phone.from_json_api(attributes["phone"]),
+            state_of_incorporation=attributes["stateOfIncorporation"], ein=attributes["ein"],
+            entity_type=attributes["entityType"],
+            contact=BusinessContact.from_json_api(attributes["contact"]),
+            authorized_users=AuthorizedUser.from_json_api(attributes["authorizedUsers"]),
+            dba=attributes.get("dba"), tags=attributes.get("tags"), relationships=relationships,
+            status=attributes.get("status"), archive_reason=attributes.get("archiveReason"),
+            eligible_products=attributes.get("eligibleProducts"),
+        )
 
 CustomerDTO = Union[IndividualCustomerDTO, BusinessCustomerDTO]
 

From bfd0f7e60a98f4baa94496653697c75fa544525a Mon Sep 17 00:00:00 2001
From: Cursor Agent <cursoragent@cursor.com>
Date: Wed, 13 May 2026 18:43:55 +0000
Subject: [PATCH 4/5] Add missing CounterpartyDTO tags field per Unit docs

Per https://docs.unit.co/resources, ACH counterparties expose a tags
attribute that the DTO was not deserializing.

Co-authored-by: Avery Kushner <avesk@users.noreply.github.com>
---
 unit/models/counterparty.py | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/unit/models/counterparty.py b/unit/models/counterparty.py
index 987c4ba..01415a1 100644
--- a/unit/models/counterparty.py
+++ b/unit/models/counterparty.py
@@ -8,19 +8,23 @@
 class CounterpartyDTO(object):
     def __init__(self, id: str, created_at: datetime, name: str, routing_number: str, bank: Optional[str],
                  account_number: str, account_type: str, type: str, permissions: str,
-                 relationships: [Dict[str, Relationship]]):
+                 relationships: [Dict[str, Relationship]], tags: Optional[Dict[str, str]] = None):
         self.id = id
         self.type = "achCounterparty"
         self.attributes = {"createdAt": created_at, "name": name, "routingNumber": routing_number, "bank": bank,
                            "accountNumber": account_number, "accountType": account_type, "type": type,
-                           "permissions": permissions}
+                           "permissions": permissions, "tags": tags}
         self.relationships = relationships
 
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
-        return CounterpartyDTO(_id, date_utils.to_datetime(attributes["createdAt"]), attributes["name"],
-                               attributes["routingNumber"], attributes.get("bank"), attributes["accountNumber"],
-                               attributes["accountType"], attributes["type"], attributes["permissions"], relationships)
+        return CounterpartyDTO(
+            id=_id, created_at=date_utils.to_datetime(attributes["createdAt"]), name=attributes["name"],
+            routing_number=attributes["routingNumber"], bank=attributes.get("bank"),
+            account_number=attributes["accountNumber"], account_type=attributes["accountType"],
+            type=attributes["type"], permissions=attributes["permissions"], relationships=relationships,
+            tags=attributes.get("tags"),
+        )
 
 
 class CreateCounterpartyRequest(UnitRequest):

From 4eab9a2eda8a5400ba82a4e45be090636f443735 Mon Sep 17 00:00:00 2001
From: Cursor Agent <cursoragent@cursor.com>
Date: Wed, 13 May 2026 18:44:03 +0000
Subject: [PATCH 5/5] Add DisputeDTO updatedAt field and fix from_json_api
 kwargs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Per https://docs.unit.co/resources, Dispute exposes an optional updatedAt
attribute. Also switch from_json_api to use keyword arguments — the
previous positional call assigned attributes to the wrong constructor
parameters (createdAt was being passed as 'source', etc.) but happened
to work since values were stored in self.attributes by name in __init__.

Co-authored-by: Avery Kushner <avesk@users.noreply.github.com>
---
 unit/models/dispute.py | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/unit/models/dispute.py b/unit/models/dispute.py
index ca3f6fb..0b7bdfe 100644
--- a/unit/models/dispute.py
+++ b/unit/models/dispute.py
@@ -18,16 +18,18 @@ def __init__(
         status_history: List[Dict[str, str]],
         status: DisputeStatus,
         description: str,
-        dispute_type: str,
+        dispute_type: Optional[str],
         created_at: datetime,
         amount: int,
         decision_reason: Optional[str],
         relationships: Optional[Dict[str, Relationship]],
+        updated_at: Optional[datetime] = None,
     ):
         self.id = id
         self.type = "dispute"
         self.attributes = {
             "createdAt": created_at,
+            "updatedAt": updated_at,
             "source": source,
             "statusHistory": status_history,
             "status": status,
@@ -41,14 +43,15 @@ def __init__(
     @staticmethod
     def from_json_api(_id, _type, attributes, relationships):
         return DisputeDTO(
-            _id,
-            date_utils.to_datetime(attributes["createdAt"]),
-            attributes["source"],
-            attributes["statusHistory"],
-            attributes["status"],
-            attributes["description"],
-            attributes["disputeType"],
-            attributes["amount"],
-            attributes.get("decisionReason"),
-            relationships,
+            id=_id,
+            source=attributes["source"],
+            status_history=attributes["statusHistory"],
+            status=attributes["status"],
+            description=attributes["description"],
+            dispute_type=attributes.get("disputeType"),
+            created_at=date_utils.to_datetime(attributes["createdAt"]),
+            amount=attributes["amount"],
+            decision_reason=attributes.get("decisionReason"),
+            relationships=relationships,
+            updated_at=date_utils.to_datetime(attributes.get("updatedAt")) if attributes.get("updatedAt") else None,
         )
