Skip to content

Transaction Builder API

Create and manage transaction builders with full participant and property management capabilities.


Overview

Transaction Builder Workflow

The Transaction Builder API allows you to:

  • Create new transaction builders for various types of real estate transactions
  • Configure property details, participants, and financial information
  • Manage buyers, sellers, agents, and other transaction participants
  • Submit completed transactions for processing
  • Convert listings to transactions
  • Backward Compatibility with legacy method names

🚨 CRITICAL API REQUIREMENTS

These requirements are MANDATORY for successful API calls:

Location Updates: - Basic address fields (street, city, state, zip) alone will FAIL - Additional fields are REQUIRED: county, yearBuilt, mlsNumber

Price/Date Updates: - Basic price fields alone will FAIL - BOTH commission objects are REQUIRED: listingCommission AND saleCommission

Co-Agent Roles: - ✅ Working: "REAL", "BUYERS_AGENT", "SELLERS_AGENT" - ❌ Fails: "LISTING_AGENT"

Owner Agents: - Require specific sequence: location → price/date → participants → owner agent - Need valid officeId and teamId


Quick Start

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Step 1: Create transaction builder
transaction_id: str = client.transaction_builder.create_transaction_builder()

# Step 2: Add property information - CRITICAL REQUIREMENTS
# ⚠️ Additional fields beyond basic address are REQUIRED
location_data: Dict[str, Any] = {
    "street": "123 Main Street",  # Use 'street' not 'address'
    "city": "Salt Lake City",
    "state": "UTAH",  # MUST BE ALL CAPS
    "zip": "84101",   # Use 'zip' not 'zipCode'
    "county": "Salt Lake",      # REQUIRED - API fails without this
    "yearBuilt": 2020,         # REQUIRED - API fails without this
    "mlsNumber": "MLS123456"   # REQUIRED - API fails without this
}
client.transaction_builder.update_location_info(transaction_id, location_data)

# Step 3: Add price/date information - CRITICAL REQUIREMENTS
# ⚠️ BOTH commission objects are REQUIRED together
price_data: Dict[str, Any] = {
    "dealType": "COMPENSATING",
    "propertyType": "RESIDENTIAL",
    "salePrice": {"amount": 500000, "currency": "USD"},
    "representationType": "BUYER",
    "listingCommission": {     # REQUIRED - cannot omit
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    },
    "saleCommission": {        # REQUIRED - cannot omit
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    }
}
client.transaction_builder.update_price_and_date_info(transaction_id, price_data)

# Step 4: Add participants (use camelCase)
buyer_data: Dict[str, Any] = {
    "firstName": "John",  # Use camelCase
    "lastName": "Doe",    # Use camelCase
    "email": "john.doe@email.com",
    "phoneNumber": "(555) 123-4567"  # Use camelCase
}
client.transaction_builder.add_buyer(transaction_id, buyer_data)

# Step 5: Add co-agent (working roles only)
co_agent_data: Dict[str, Any] = {
    "agentId": "bd465129-b224-43e3-b92f-524ea5f53783",
    "role": "REAL",  # ✅ Working role
    "receivesInvoice": False
}
client.transaction_builder.add_co_agent(transaction_id, co_agent_data)

# Step 6: Submit transaction
client.transaction_builder.submit_transaction(transaction_id)
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Create listing builder using dedicated method
listing_id: str = client.transaction_builder.create_listing_builder()

# Configure listing-specific details (use camelCase)
seller_data: Dict[str, Any] = {
    "firstName": "Jane",      # Use camelCase
    "lastName": "Smith",      # Use camelCase
    "email": "jane.smith@email.com",
    "phoneNumber": "(555) 987-6543"  # Use camelCase
}
client.transaction_builder.add_seller(listing_id, seller_data)
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Convert existing listing to transaction
listing_id: str = "existing-listing-id"
response: Dict[str, Any] = client.transaction_builder.convert_listing_to_transaction(listing_id)
transaction_id: str = response['id']
print(f"Converted listing {listing_id} to transaction {transaction_id}")

Core Transaction Management

Create Transaction Builder

Create empty transaction builder.

This is the starting point for creating a new transaction. After creation, you'll receive a transaction ID that you'll use for all subsequent operations.

⚠️ CRITICAL: Follow the recommended workflow for successful transaction creation. Many endpoints require specific data to be present before they will work.

Successful Working Example
# Complete working sequence with co-agent
client = RezenClient()

# 1. Create transaction
transaction_id = client.transaction_builder.create_transaction_builder()

# 2. Add location (with required additional fields)
location_data = {
    "street": "123 Main Street",
    "city": "Salt Lake City",
    "state": "UTAH",
    "zip": "84101",
    "county": "Salt Lake",      # REQUIRED
    "yearBuilt": 2020,         # REQUIRED
    "mlsNumber": "MLS123456"   # REQUIRED
}
client.transaction_builder.update_location_info(transaction_id, location_data)

# 3. Add price/date (with both commission objects)
price_data = {
    "dealType": "COMPENSATING",
    "propertyType": "RESIDENTIAL",
    "salePrice": {"amount": 550000, "currency": "USD"},
    "representationType": "BUYER",
    "listingCommission": {     # REQUIRED
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    },
    "saleCommission": {        # REQUIRED
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    }
}
client.transaction_builder.update_price_and_date_info(transaction_id, price_data)

# 4. Add participants
client.transaction_builder.add_buyer(transaction_id, {
    "firstName": "John",
    "lastName": "Buyer",
    "email": "john@example.com",
    "phoneNumber": "(801) 555-1234"
})

# 5. Add co-agent (this works immediately)
co_agent_info = {
    "agentId": "bd465129-b224-43e3-b92f-524ea5f53783",
    "role": "REAL",
    "receivesInvoice": False
}
client.transaction_builder.add_co_agent(transaction_id, co_agent_info)

# Result: Complete working transaction with co-agent
print(f"✅ Successfully created transaction {transaction_id} with co-agent")
Builder Types
  • "TRANSACTION": Standard real estate transaction
  • "LISTING": Property listing

Parameters:

Name Type Description Default
builder_type str

Type of builder to create ("TRANSACTION" or "LISTING")

'TRANSACTION'

Returns:

Type Description
str

Transaction builder ID as string

Raises:

Type Description
ValidationError

If builder_type is invalid

RezenError

If transaction creation fails

Consistent Response Format

The method now returns a consistent {"id": "transaction_id"} format instead of a raw string.

Create Listing Builder

Create a listing builder (wrapper for create_transaction_builder).

Returns:

Type Description
str

Listing builder ID

Convenience Method

This is a wrapper around create_transaction_builder(builder_type='LISTING') for easier listing creation.

Convert Listing to Transaction

Convert a listing to a transaction (wrapper for create_builder_from_transaction).

Parameters:

Name Type Description Default
listing_id str

Listing ID to convert

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Create Different Builder Types

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Standard transaction builder
response: Dict[str, Any] = client.transaction_builder.create_transaction_builder()
print(f"Transaction ID: {response['id']}")
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Using dedicated listing builder method
response: Dict[str, Any] = client.transaction_builder.create_listing_builder()
print(f"Listing ID: {response['id']}")
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Convert listing to transaction
listing_id = "existing-listing-id"
response: Dict[str, Any] = client.transaction_builder.convert_listing_to_transaction(listing_id)
print(f"New transaction ID: {response['id']}")

Get Transaction Builder

Get a specific transaction builder by ID.

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required

Returns:

Type Description
Dict[str, Any]

Transaction builder data

Response Structure

The transaction builder response includes:

  • Basic Information: ID, type, status, creation date
  • Participants: All buyers, sellers, agents, and other participants
  • Property Details: Location, pricing, and property information
  • Financial Data: Commission splits and payment information

Submit Transaction

Submit a transaction builder to create a transaction.

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required

Returns:

Type Description
Dict[str, Any]

Transaction preview response data

Submission Requirements

Before submitting, ensure:

  • At least one participant is added
  • Property location is specified
  • Required financial information is complete
  • All mandatory fields are populated

Delete Transaction Builder

Delete transaction builder.

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required

Returns:

Type Description
Dict[str, Any]

Deletion response data

Deletion Warning

This operation is irreversible. Ensure you have backups of any critical data before deletion.


Participant Management

Buyers

Add a new buyer.

Important: Use camelCase for field names: - firstName (not first_name) - lastName (not last_name) - phoneNumber (not phone_number)

Example

buyer_info = { "firstName": "John", "lastName": "Doe", "email": "john.doe@example.com", "phoneNumber": "(555) 123-4567" }

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
buyer_info Dict[str, Any]

Buyer information data with camelCase fields

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Required Buyer Fields:

Field Type Description
firstName str Buyer's first name (camelCase)
lastName str Buyer's last name (camelCase)
email str Valid email address

Optional Buyer Fields:

Field Type Description
phoneNumber str Phone number (camelCase)
company str Company name
address str Mailing address

Complete Buyer Example

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

buyer_data: Dict[str, Any] = {
    "firstName": "John",  # Use camelCase
    "lastName": "Doe",  # Use camelCase
    "email": "john.doe@email.com",
    "phoneNumber": "+1-555-123-4567",  # Use camelCase
    "company": "Doe Enterprises",
    "address": "456 Business Ave, Business City, BC 12345"
}

# Using new method name
response: Dict[str, Any] = client.transaction_builder.add_buyer(transaction_id, buyer_data)

# Or using backward compatibility alias
response: Dict[str, Any] = client.transaction_builder.put_buyer_to_draft(transaction_id, buyer_data)

Sellers

Add a new seller to a transaction builder.

Important: Use camelCase for field names: - firstName (not first_name) - lastName (not last_name) - phoneNumber (not phone_number)

Example

seller_info = { "firstName": "Jane", "lastName": "Smith", "email": "jane.smith@example.com", "phoneNumber": "(555) 987-6543" }

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
seller_info Dict[str, Any]

Seller information data with camelCase fields

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Seller Configuration

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

seller_data: Dict[str, Any] = {
    "firstName": "Jane",  # Use camelCase
    "lastName": "Smith",  # Use camelCase
    "email": "jane.smith@email.com",
    "phoneNumber": "+1-555-987-6543"  # Use camelCase
}

# Using new method name
response: Dict[str, Any] = client.transaction_builder.add_seller(transaction_id, seller_data)

# Or using backward compatibility alias
response: Dict[str, Any] = client.transaction_builder.put_seller_to_draft(transaction_id, seller_data)

Agents & Co-Agents

Add a new co-agent to the transaction.

Co-agents can be added at any time after transaction creation, unlike owner agents which require a specific sequence. The co-agent will appear in the transaction's agentsInfo.coAgents array.

⚠️ ROLE LIMITATIONS ⚠️ Based on testing, only certain roles work with co-agents:

✅ WORKING ROLES: - "REAL" - Always works (may display differently based on representationType) - "BUYERS_AGENT" - Works on transactions with location data - "SELLERS_AGENT" - Works on transactions with location data

❌ NON-WORKING ROLES: - "LISTING_AGENT" - Fails with "Bad request: Invalid request"

Required Fields
  • agentId (str): UUID of the co-agent (must be a valid agent ID)
  • role (str): Agent role - use one of the working roles above
  • receivesInvoice (bool): Whether the co-agent receives invoice
Optional Fields
  • opCityReferral (bool): Whether this is an OpCity referral (default: False)
  • optedInForEcp (bool): Whether opted in for ECP (default: False)
Note on Role Display

The role field accepts "REAL" but may be displayed differently in the response based on the transaction's representationType. For example, if representationType is "BUYER", a co-agent with role "REAL" may appear as "BUYERS_AGENT" in the response.

Working Examples
# ✅ Co-agent with REAL role (always works)
co_agent_info = {
    "agentId": "bd465129-b224-43e3-b92f-524ea5f53783",
    "role": "REAL",
    "receivesInvoice": False,
    "opCityReferral": False,
    "optedInForEcp": False
}
result = client.add_co_agent(transaction_id, co_agent_info)

# ✅ Co-agent with BUYERS_AGENT role (works with location data)
co_agent_info = {
    "agentId": "bd465129-b224-43e3-b92f-524ea5f53783",
    "role": "BUYERS_AGENT",
    "receivesInvoice": False
}
result = client.add_co_agent(transaction_id, co_agent_info)

# ❌ This FAILS (LISTING_AGENT role not supported)
co_agent_info = {
    "agentId": "bd465129-b224-43e3-b92f-524ea5f53783",
    "role": "LISTING_AGENT",  # This role fails
    "receivesInvoice": False
}
# Will return "Bad request: Invalid request"

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
co_agent_info Dict[str, Any]

Co-agent information data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data with updated co-agents list

Raises:

Type Description
ValidationError

If role is not supported or agent ID is invalid

Agent Roles:

Available Agent Roles

  • BUYERS_AGENT: Represents the buyer
  • SELLERS_AGENT: Represents the seller
  • LISTING_AGENT: Lists the property
  • DUAL_AGENT: Represents both parties

Co-Agent Examples

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

co_agent_data: Dict[str, Any] = {
    "agent_id": "agent-uuid-here",
    "role": "BUYERS_AGENT"
}
client.transaction_builder.add_co_agent(transaction_id, co_agent_data)
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

co_agent_data: Dict[str, Any] = {
    "agent_id": "seller-agent-uuid",
    "role": "SELLERS_AGENT"
}
client.transaction_builder.add_co_agent(transaction_id, co_agent_data)

Owner Agents

Update owner agent information for the transaction.

✅ WORKING SOLUTION ✅ This method now works correctly when called in the proper sequence.

🔄 REQUIRED SEQUENCE: 1. Create transaction (create_transaction_builder) 2. Add location info with ALL required fields (update_location_info) 3. Add price/date info with commission objects (update_price_and_date_info) 4. Add buyers/sellers (add_buyer/add_seller) 5. THEN add owner agent (this method) - ✅ WORKS!

📋 COMPLETE DATA REQUIREMENTS:

Location Info Must Include
  • street, city, state, zip (basic)
  • county: Required additional field
  • yearBuilt: Required additional field
  • mlsNumber: Required additional field

Price/Date Info Must Include: - dealType, propertyType, salePrice, representationType (basic) - listingCommission: Required commission object - saleCommission: Required commission object

Owner Agent Data Structure

owner_agent_info = { "ownerAgent": { "agentId": str, # User ID (same as agent ID in ReZEN) "role": str # "BUYERS_AGENT" or "SELLERS_AGENT" }, "officeId": str, # From user.offices[0].id "teamId": str # UUID of the team }

🎯 GETTING THE RIGHT IDS: - agentId: Use current user's ID (user["id"] from get_current_user()) - officeId: Use user["offices"][0]["id"] from get_current_user() - teamId: Use team ID from get_user_teams_and_offices()

Role Matching

The role MUST match the representationType from price/date info: - representationType: "BUYER" → role: "BUYERS_AGENT" - representationType: "SELLER" → role: "SELLERS_AGENT"

💡 TIP: Use convenience methods instead of manual setup: - set_current_user_as_owner_agent() for default team - set_current_user_as_owner_agent_with_team() for specific team

Example - Complete Working Sequence
# 1. Create transaction
builder_id = client.transaction_builder.create_transaction_builder()

# 2. Add location with ALL required fields (REQUIRED FIRST)
client.transaction_builder.update_location_info(builder_id, {
    "street": "123 Main St",
    "city": "Salt Lake City",
    "state": "UTAH",
    "zip": "84101",
    "county": "Salt Lake",        # REQUIRED
    "yearBuilt": 2020,           # REQUIRED
    "mlsNumber": "MLS-123456"    # REQUIRED
})

# 3. Add price/date with commission objects (REQUIRED SECOND)
client.transaction_builder.update_price_and_date_info(builder_id, {
    "dealType": "COMPENSATING",
    "propertyType": "RESIDENTIAL",
    "salePrice": {"amount": 500000, "currency": "USD"},
    "representationType": "BUYER",
    "listingCommission": {       # REQUIRED
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    },
    "saleCommission": {          # REQUIRED
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    }
})

# 4. Add buyer (REQUIRED THIRD)
client.transaction_builder.add_buyer(builder_id, {
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "phoneNumber": "(555) 123-4567"
})

# 5. Get user and office info
user = client.users.get_current_user()

# 6. NOW add owner agent (WORKS!)
owner_info = {
    "ownerAgent": {
        "agentId": user["id"],          # User ID = Agent ID
        "role": "BUYERS_AGENT"          # Must match representationType
    },
    "officeId": user["offices"][0]["id"],  # From user's offices
    "teamId": "your-team-uuid"              # Your team ID
}
result = client.transaction_builder.update_owner_agent_info(builder_id, owner_info)

Parameters:

Name Type Description Default
transaction_builder_id str

UUID of the transaction builder

required
owner_agent_info Dict[str, Any]

Dictionary containing owner agent details

required

Returns:

Type Description
Dict[str, Any]

Updated transaction builder data

Raises:

Type Description
ValidationError

If owner agent info is invalid or sequence not followed

NotFoundError

If transaction builder not found

Multiple Teams Support

✅ New Feature: Multiple Teams Support

Many ReZEN users belong to multiple teams. These convenience methods help handle team selection automatically:

Get current user's teams and offices with smart default selection.

✅ WORKING METHOD - Handles multiple team scenarios automatically.

This method helps handle users who belong to multiple teams by: 1. Fetching all teams the user belongs to 2. Determining a smart default team (prefers LEADER role over ADMIN) 3. Extracting office information from user profile 4. Providing clear guidance on team selection

🎯 SMART DEFAULT LOGIC: - If user has LEADER role in any team → that team becomes default - If user only has ADMIN roles → first ADMIN team becomes default - If user has only one team → that team becomes default

💡 USE CASES: - Check if user needs team selection before transaction creation - Get default team for automatic owner agent setup - Display available teams for user selection

Parameters:

Name Type Description Default
users_client Optional[Any]

Optional users client instance (uses parent client if None)

None

Returns:

Type Description
Dict[str, Any]

Dictionary containing:

Dict[str, Any]
  • user: Full user profile data with offices array
Dict[str, Any]
  • teams: List of teams user belongs to with roles
Dict[str, Any]
  • offices: List of offices user belongs to
Dict[str, Any]
  • default_team: Recommended team (smart selection)
Dict[str, Any]
  • has_multiple_teams: Boolean indicating if user has multiple teams
Dict[str, Any]
  • team_selection_needed: Boolean indicating if explicit selection recommended
Dict[str, Any]
  • agent_id: User's agent ID (same as user ID)
Dict[str, Any]
  • office_id: Primary office ID from user.offices[0].id
Example
info = client.transaction_builder.get_user_teams_and_offices()

print(f"Agent ID: {info['agent_id']}")
print(f"Office ID: {info['office_id']}")

if info["has_multiple_teams"]:
    print("\nAvailable teams:")
    for team in info["teams"]:
        role = team["role"]
        name = team["name"]
        is_default = team["id"] == info["default_team"]["id"]
        marker = " (DEFAULT)" if is_default else ""
        print(f"  - {name} (Role: {role}){marker}")

    # Use default team or let user choose
    selected_team = info["default_team"]
    print(f"\nUsing default team: {selected_team['name']}")
else:
    print(f"Single team: {info['default_team']['name']}")

# Ready-to-use IDs for transaction setup
team_id = info["default_team"]["id"]
office_id = info["office_id"]
agent_id = info["agent_id"]
Team Data Structure

Each team in the teams list contains: - id: Team UUID - name: Team name - role: User's role in the team ("LEADER", "ADMIN", etc.)

Raises:

Type Description
APIError

If user data cannot be retrieved

ValueError

If user has no offices (required for transactions)

Smart Default Logic: - Prefers teams where you have LEADER role - Falls back to ADMIN teams - Uses first available team as last resort

Set the current authenticated user as the owner agent with default team.

✅ WORKING CONVENIENCE METHOD

⚠️ MULTIPLE TEAMS WARNING ⚠️ If you belong to multiple teams, this method will use your DEFAULT team (prefers LEADER role). To specify a particular team, use set_current_user_as_owner_agent_with_team() instead.

This is a convenience method that automatically: 1. Gets current user information (user ID and office ID) 2. Determines default team using smart logic 3. Sets up owner agent with all required fields

🎯 SMART DEFAULT TEAM LOGIC: - Prefers teams where you have LEADER role - Falls back to teams where you have ADMIN role - Uses first available team as last resort

Parameters:

Name Type Description Default
transaction_builder_id str

UUID of the transaction builder

required
role str

Agent role ("BUYERS_AGENT" or "SELLERS_AGENT")

required
users_client Optional[Any]

Optional UsersClient instance. If None, will create one.

None

Returns:

Type Description
Dict[str, Any]

Updated transaction builder data

Raises:

Type Description
ValidationError

If owner agent info is invalid or user has no teams

NotFoundError

If transaction builder not found

AuthenticationError

If not authenticated

ValueError

If user has no offices

Example
# Simple case - uses default team automatically
result = client.transaction_builder.set_current_user_as_owner_agent(
    builder_id,
    "BUYERS_AGENT"
)

# For multiple teams - check first, then choose approach
teams_info = client.transaction_builder.get_user_teams_and_offices()

if teams_info["has_multiple_teams"]:
    print(f"You have {len(teams_info['teams'])} teams.")
    print(f"Will use default: {teams_info['default_team']['name']}")

    # Option 1: Use this method with default team
    result = client.transaction_builder.set_current_user_as_owner_agent(
        builder_id, "BUYERS_AGENT"
    )

    # Option 2: Specify team explicitly
    # result = client.transaction_builder.set_current_user_as_owner_agent_with_team(
    #     builder_id, "BUYERS_AGENT", teams_info["teams"][1]["id"]
    # )
else:
    # Single team - use this convenience method
    result = client.transaction_builder.set_current_user_as_owner_agent(
        builder_id, "BUYERS_AGENT"
    )

Best for: Users with single team or who want automatic team selection.

Set current user as owner agent with explicit team selection.

✅ WORKING CONVENIENCE METHOD

This method allows users to specify which team to use when they belong to multiple teams. This gives full control over team selection and is recommended when you need to be explicit about which team to use.

🎯 PERFECT FOR: - Users who belong to multiple teams - When you need specific team for business reasons - Programmatic team selection based on criteria

This method automatically: 1. Gets current user information (user ID and office ID) 2. Validates the user belongs to the specified team 3. Sets up owner agent with all required fields

Parameters:

Name Type Description Default
transaction_builder_id str

UUID of the transaction builder

required
role str

Agent role ("BUYERS_AGENT" or "SELLERS_AGENT")

required
team_id str

Specific team ID to use for the transaction

required
users_client Optional[Any]

Optional UsersClient instance. If None, will create one.

None

Returns:

Type Description
Dict[str, Any]

Updated transaction builder data

Raises:

Type Description
ValidationError

If user is not a member of the specified team

ValidationError

If team_id is invalid

NotFoundError

If transaction builder not found

AuthenticationError

If not authenticated

ValueError

If user has no offices

Example
# Option 1: Get available teams and choose
teams_info = client.transaction_builder.get_user_teams_and_offices()

if teams_info["has_multiple_teams"]:
    print("Available teams:")
    for team in teams_info["teams"]:
        print(f"  {team['name']} (ID: {team['id']}, Role: {team['role']})")

    # Choose a specific team (e.g., select LEADER team)
    leader_teams = [t for t in teams_info["teams"] if t["role"] == "LEADER"]
    selected_team_id = leader_teams[0]["id"] if leader_teams else teams_info["teams"][0]["id"]
else:
    selected_team_id = teams_info["default_team"]["id"]

# Set owner agent with specific team
result = client.transaction_builder.set_current_user_as_owner_agent_with_team(
    builder_id,
    role="BUYERS_AGENT",
    team_id=selected_team_id
)

# Option 2: Direct usage if you know the team ID
result = client.transaction_builder.set_current_user_as_owner_agent_with_team(
    builder_id,
    role="SELLERS_AGENT",
    team_id="12345678-1234-1234-1234-123456789012"
)

Best for: Users with multiple teams who need explicit control.

Prerequisites Required

CRITICAL: The owner agent endpoint requires the transaction to be properly set up BEFORE adding agents:

  1. Location info must be added first (update_location_info)
  2. Price and date info must be added second (update_price_and_date_info)
  3. Buyers/Sellers must be added third (add_buyer/add_seller)
  4. THEN owner agent can be added successfully

Owner Data Structure:

{
    "ownerAgent": {
        "agentId": "agent_uuid",
        "role": "BUYERS_AGENT"  # or "SELLERS_AGENT"
    },
    "officeId": "office_uuid", 
    "teamId": "team_uuid"
}

Multiple Teams Support

New in ReZEN: If you belong to multiple teams, use the enhanced methods:

  • get_user_teams_and_offices() - Discover available teams
  • set_current_user_as_owner_agent_with_team() - Specify exact team

See Multiple Teams Guide for details.

Complete Working Example

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Step 1: Create transaction
builder_id = client.transaction_builder.create_transaction_builder()

# Step 2: Add location (REQUIRED FIRST)
location_data: Dict[str, Any] = {
    "street": "123 Main St",
    "city": "Salt Lake City", 
    "state": "UTAH",
    "zip": "84101"
}
client.transaction_builder.update_location_info(builder_id, location_data)

# Step 3: Add price/date info (REQUIRED SECOND)
price_data: Dict[str, Any] = {
    "dealType": "COMPENSATING",
    "propertyType": "RESIDENTIAL", 
    "salePrice": {"amount": 500000, "currency": "USD"},
    "representationType": "BUYER"  # Must match agent role
}
client.transaction_builder.update_price_and_date_info(builder_id, price_data)

# Step 4: Add clients (REQUIRED THIRD)
client.transaction_builder.add_buyer(builder_id, {
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "phoneNumber": "(801) 555-1234"
})

# Step 5: NOW add owner agent (will work!)
owner_data: Dict[str, Any] = {
    "ownerAgent": {
        "agentId": "your_agent_id",
        "role": "BUYERS_AGENT"  # Must match representationType
    },
    "officeId": "your_office_id",
    "teamId": "your_team_id"
}
client.transaction_builder.update_owner_agent_info(builder_id, owner_data)
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()

# Set up transaction (same steps 1-4 as above)
builder_id = client.transaction_builder.create_transaction_builder()
# ... add location, price, and clients ...

# Use convenience method for current user
client.transaction_builder.set_current_user_as_owner_agent(
    builder_id, 
    role="BUYERS_AGENT"
)

Role Matching

The role in ownerAgent must match the representationType in the price/date info:

  • representationType: "BUYER"role: "BUYERS_AGENT"
  • representationType: "SELLER"role: "SELLERS_AGENT"

Other Participants

Add a new participant to the transaction builder.

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
participant_info Dict[str, Any]

Participant information data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Participant Types:

Type Description
INSPECTOR Property inspector
APPRAISER Property appraiser
LENDER Mortgage lender
TITLE_COMPANY Title company representative
ATTORNEY Legal counsel
CONTRACTOR Contractor or repair specialist

Service Provider Examples

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

inspector_data: Dict[str, Any] = {
    "type": "INSPECTOR",
    "firstName": "Mike",  # Use camelCase
    "lastName": "Inspector",  # Use camelCase
    "company": "Quality Inspections Inc",
    "phoneNumber": "+1-555-INSPECT",  # Use camelCase
    "email": "mike@qualityinspections.com"
}
client.transaction_builder.add_participant(transaction_id, inspector_data)
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

lender_data: Dict[str, Any] = {
    "type": "LENDER",
    "firstName": "Sarah",  # Use camelCase
    "lastName": "Banker",  # Use camelCase
    "company": "First National Bank",
    "phoneNumber": "+1-555-LOANS",  # Use camelCase
    "email": "sarah.banker@firstnational.com"
}
client.transaction_builder.add_participant(transaction_id, lender_data)

Property & Location Details

Location Information

Update location information.

⚠️ CRITICAL REQUIREMENT ⚠️ Basic address fields alone (street, city, state, zip) will FAIL. The API requires additional property details for successful location updates.

REQUIRED ADDITIONAL FIELDS (beyond basic address): - county (str): County name (e.g., "Salt Lake") - yearBuilt (int): Year the property was built (e.g., 2020) - mlsNumber (str): MLS listing number (e.g., "MLS123456")

Field Name Requirements
  • Use 'street' not 'address'
  • Use 'zip' not 'zipCode' or 'zip_code'
  • State must be ALL CAPS (e.g., 'UTAH', 'CALIFORNIA')
  • Use camelCase for: yearBuilt, mlsNumber, escrowNumber
Required Fields for Success
  • street (str): Property street address
  • city (str): City name
  • state (str): State name in ALL CAPS
  • zip (str): ZIP code
  • county (str): County name - REQUIRED
  • yearBuilt (int): Year built - REQUIRED
  • mlsNumber (str): MLS number - REQUIRED
Optional Fields
  • street2 (str): Secondary address line
  • unit (str): Unit number
  • escrowNumber (str): Escrow number
Working Example
# ✅ This WORKS (includes required additional fields)
location_info = {
    "street": "123 Main Street",
    "city": "Salt Lake City",
    "state": "UTAH",
    "zip": "84101",
    "county": "Salt Lake",        # REQUIRED
    "yearBuilt": 2020,           # REQUIRED
    "mlsNumber": "MLS123456",    # REQUIRED
    "escrowNumber": "ESC-2024-001"  # Optional
}

# ❌ This FAILS (missing required additional fields)
location_info = {
    "street": "123 Main Street",
    "city": "Salt Lake City",
    "state": "UTAH",
    "zip": "84101"
    # Missing county, yearBuilt, mlsNumber - API returns "Bad request: Invalid request"
}

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
location_info Dict[str, Any]

Location information data with ALL required fields

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Raises:

Type Description
InvalidFieldNameError

If using wrong field names (address, zipCode, etc.)

InvalidFieldValueError

If state is not in ALL CAPS

ValidationError

If missing required additional fields

Backward Compatibility

You can also use put_location_to_draft() which is an alias for update_location_info().

Property Location Examples

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

location_data: Dict[str, Any] = {
    "street": "123 Maple Street",  # Use 'street' not 'address'
    "street2": "",
    "city": "Springfield",
    "state": "UTAH",  # Must be UTAH (all caps)
    "zip": "84101",  # Use 'zip' not 'zipCode'
    "county": "Salt Lake",
    "unit": "Unit 2A",  # For condos/apartments
    "subdivision": "Maple Grove",
    "yearBuilt": 2020,  # Use camelCase
    "mlsNumber": "MLS123",  # Use camelCase
    "escrowNumber": ""
}

# Using new method name
client.transaction_builder.update_location_info(transaction_id, location_data)

# Or using backward compatibility alias
client.transaction_builder.put_location_to_draft(transaction_id, location_data)
from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

location_data: Dict[str, Any] = {
    "street": "456 Business Blvd",  # Use 'street' not 'address'
    "street2": "",
    "city": "Commerce City",
    "state": "UTAH",  # Must be UTAH (all caps)
    "zip": "84111",  # Use 'zip' not 'zipCode'
    "county": "Salt Lake",
    "yearBuilt": 2018,
    "mlsNumber": "COM456",
    "escrowNumber": "",
    "building_name": "Commerce Center",
    "floor": "15th Floor"
}
client.transaction_builder.update_location_info(transaction_id, location_data)

Pricing & Dates

Update price and date information.

⚠️ CRITICAL REQUIREMENT ⚠️ Basic price/date fields alone will FAIL with "Bad request: Invalid request". The API requires BOTH commission objects for successful price/date updates.

REQUIRED COMMISSION FIELDS

Both listingCommission AND saleCommission objects are REQUIRED together. You cannot provide just one - the API needs both.

Field Structure Requirements
  • salePrice MUST be an object with 'amount' and 'currency', NOT a simple number
  • All dates use camelCase format: acceptanceDate, closingDate, etc.
  • representationType determines valid agent roles (BUYER → BUYERS_AGENT, SELLER → SELLERS_AGENT)
Required Fields for Success
  • dealType (str): "COMPENSATING" or "NON_COMPENSATING"
  • propertyType (str): "RESIDENTIAL", "COMMERCIAL", etc.
  • salePrice (dict): {"amount": 500000, "currency": "USD"}
  • representationType (str): "BUYER" or "SELLER" - affects owner agent role
  • listingCommission (dict): Commission object - REQUIRED
  • saleCommission (dict): Commission object - REQUIRED
Optional Fields
  • acceptanceDate (str): Date in "YYYY-MM-DD" format
  • closingDate (str): Date in "YYYY-MM-DD" format
  • earnestMoney (float): Earnest money amount
  • downPayment (float): Down payment amount
  • loanAmount (float): Loan amount
Working Example
# ✅ This WORKS (includes both required commission objects)
price_date_info = {
    "dealType": "COMPENSATING",
    "propertyType": "RESIDENTIAL",
    "salePrice": {
        "amount": 565000,
        "currency": "USD"
    },
    "representationType": "BUYER",
    "listingCommission": {       # REQUIRED
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    },
    "saleCommission": {          # REQUIRED
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    },
    "acceptanceDate": "2024-01-15",
    "closingDate": "2024-02-28"
}

# ❌ This FAILS (missing commission objects)
price_date_info = {
    "dealType": "COMPENSATING",
    "propertyType": "RESIDENTIAL",
    "salePrice": {"amount": 500000, "currency": "USD"},
    "representationType": "BUYER"
    # Missing both commission objects - API returns "Bad request: Invalid request"
}

# ❌ This ALSO FAILS (only one commission object)
price_date_info = {
    "dealType": "COMPENSATING",
    "propertyType": "RESIDENTIAL",
    "salePrice": {"amount": 500000, "currency": "USD"},
    "representationType": "BUYER",
    "listingCommission": {       # Only one commission
        "commissionPercent": 3.0,
        "percentEnabled": True,
        "negativeOrEmpty": False
    }
    # Missing saleCommission - API still returns "Bad request: Invalid request"
}

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
price_date_info Dict[str, Any]

Price and date information data with BOTH commission objects

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Raises:

Type Description
ValidationError

If missing required fields or commission objects

InvalidFieldValueError

If salePrice format is incorrect or representationType invalid

Backward Compatibility

You can also use put_price_and_date_to_draft() which is an alias for update_price_and_date_info().

Key Date Fields:

Field Format Description
contractDate YYYY-MM-DD Date contract was signed (camelCase)
closingDate YYYY-MM-DD Expected closing date (camelCase)
inspectionDate YYYY-MM-DD Property inspection date (camelCase)
appraisalDate YYYY-MM-DD Appraisal completion date (camelCase)
acceptanceDate YYYY-MM-DD Offer acceptance date (camelCase)

Pricing Information

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

price_date_data: Dict[str, Any] = {
    "salePrice": {  # Use camelCase and object structure
        "amount": 750000,
        "currency": "USD"
    },
    "earnestMoney": 15000,  # Use camelCase
    "downPayment": 150000,  # Use camelCase
    "loanAmount": 600000,  # Use camelCase
    "contractDate": "2024-02-01",  # Use camelCase
    "closingDate": "2024-03-15",  # Use camelCase
    "inspectionDate": "2024-02-10",  # Use camelCase
    "appraisalDate": "2024-02-20"  # Use camelCase
}

client.transaction_builder.update_price_and_date_info(
    transaction_id,
    price_date_data
)

Title Information

Update title details for a transaction builder.

Important: Use camelCase for field names: - firstName (not first_name) - lastName (not last_name) - phoneNumber (not phone_number)

Example

title_info = { "company": "Premier Title Company", "firstName": "Sarah", "lastName": "Johnson", "email": "sarah@premiertitle.com", "phoneNumber": "(555) 555-5555" }

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
title_info Dict[str, Any]

Title information data with camelCase fields

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Update Real Title

Update real title (alias for update_title_info).

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
title_info Dict[str, Any]

Title information data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Alias Method

This is an alias for update_title_info() provided for backward compatibility.

Title Company Details

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

title_data: Dict[str, Any] = {
    "company": "Premier Title Co",  # Use 'company' not 'title_company'
    "firstName": "Sarah",  # Use camelCase
    "lastName": "Johnson",  # Use camelCase
    "phoneNumber": "+1-555-789-0123",  # Use camelCase
    "email": "sarah@premiertitle.com",
    "address": "789 Title Lane, Title City, TC 54321",
    "policyNumber": "PT-2024-001234"  # Use camelCase
}

# Using either method works the same
client.transaction_builder.update_title_info(transaction_id, title_data)
# or
client.transaction_builder.update_real_title(transaction_id, title_data)

Personal Deal Information

Update personal deal information.

Sets whether this transaction is a personal deal (agent buying/selling own property).

Required Fields
  • isPersonalDeal (bool): Whether this is a personal deal
Example
deal_info = {
    "isPersonalDeal": True  # Agent is buying/selling their own property
}
client.update_personal_deal_info(transaction_id, deal_info)

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
deal_info Dict[str, Any]

Personal deal information data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Update Personal Deal

Update personal deal (alias for update_personal_deal_info).

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
deal_info Dict[str, Any]

Personal deal information data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Alias Method

This is an alias for update_personal_deal_info() provided for backward compatibility.


Financial Management

Commission Splits

Update commission splits information.

IMPORTANT: Pass a LIST of commission split objects, even for a single split.

Commission Split Structure

Each split in the list should contain: - agentId (str): UUID of the agent receiving the split - receivesInvoice (bool): Whether this agent receives an invoice - splitPercent (float): Percentage of commission (e.g., 50.0 for 50%) - opCityReferral (bool): Whether this is an OpCity referral (optional) - optedInForEcp (bool): Whether opted in for ECP (optional)

Example
commission_splits = [
    {
        "agentId": "agent-uuid-1",
        "receivesInvoice": True,
        "splitPercent": 50.0,
        "opCityReferral": False,
        "optedInForEcp": False
    },
    {
        "agentId": "agent-uuid-2",
        "receivesInvoice": False,
        "splitPercent": 50.0,
        "opCityReferral": False,
        "optedInForEcp": False
    }
]
client.update_commission_splits(transaction_id, commission_splits)

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
commission_splits List[Dict[str, Any]]

List of commission split data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Commission Split Examples

from typing import Dict, List, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

commission_data: List[Dict[str, Any]] = [
    {
        "agentId": "buyer-agent-uuid",  # Use camelCase
        "splitPercentage": 50.0,  # Use camelCase
        "commissionAmount": 15000  # Use camelCase
    },
    {
        "agentId": "seller-agent-uuid",  # Use camelCase
        "splitPercentage": 50.0,  # Use camelCase
        "commissionAmount": 15000  # Use camelCase
    }
]

client.transaction_builder.update_commission_splits(
    transaction_id,
    commission_data
)
from typing import Dict, List, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

commission_data: List[Dict[str, Any]] = [
    {
        "agentId": "listing-agent-uuid",  # Use camelCase
        "splitPercentage": 60.0,  # Use camelCase
        "commissionAmount": 18000  # Use camelCase
    },
    {
        "agentId": "buyer-agent-uuid",  # Use camelCase
        "splitPercentage": 40.0,  # Use camelCase
        "commissionAmount": 12000  # Use camelCase
    }
]

client.transaction_builder.update_commission_splits(
    transaction_id,
    commission_data
)

Commission Payers

Add commission payer information.

IMPORTANT: This endpoint requires multipart/form-data format. The method automatically handles the conversion for you.

Required Fields
  • role (str): Commission payer role (e.g., "REAL", "NA", "LISTING_AGENT", "BUYERS_AGENT")
Optional Fields
  • receivesInvoice (bool): Whether the payer receives invoice
  • opCityReferral (bool): Whether this is an OpCity referral
  • optedInForEcp (bool): Whether opted in for ECP
Special Note

Based on testing, the "role" field accepts specific values that may differ from what's shown in API documentation. Common working values include: - "REAL" - For standard commission payers - "NA" - Not applicable/none - Role values matching agent roles (LISTING_AGENT, BUYERS_AGENT, etc.)

Example
commission_info = {
    "role": "REAL",
    "receivesInvoice": True,
    "opCityReferral": False,
    "optedInForEcp": False
}
client.add_commission_payer(transaction_id, commission_info)

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
commission_info Dict[str, Any]

Commission payer information data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Update Commission Payer

Update commission payer information (alias for add_commission_payer).

Parameters:

Name Type Description Default
transaction_id str

Transaction builder ID

required
commission_info Dict[str, Any]

Commission payer information data

required

Returns:

Type Description
Dict[str, Any]

Transaction builder response data

Alias Method

This is an alias for add_commission_payer() provided for backward compatibility.

Payer Types:

Type Description
SELLER Seller pays commission
BUYER Buyer pays commission
BOTH Split between buyer and seller

Commission Payer Configuration

from typing import Dict, Any

from rezen import RezenClient

client: RezenClient = RezenClient()
transaction_id: str = "your-transaction-id-here"

payer_data: Dict[str, Any] = {
    "payerType": "SELLER",  # Use camelCase
    "commissionRate": 6.0,  # 6% commission, use camelCase
    "flatFee": False  # Percentage-based, not flat fee, use camelCase
}

# Using either method works the same
client.transaction_builder.add_commission_payer(transaction_id, payer_data)
# or
client.transaction_builder.update_commission_payer(transaction_id, payer_data)

Field Name Requirements

Critical Field Name Requirements

The ReZEN API has specific field name requirements that must be followed exactly:

Location Fields: - ✅ Use street NOT address - ✅ Use zip NOT zipCode - ✅ State must be UTAH (all caps) - ✅ Use camelCase: yearBuilt, mlsNumber, escrowNumber

Contact Fields: - ✅ Use firstName NOT first_name - ✅ Use lastName NOT last_name - ✅ Use phoneNumber NOT phone

Price Fields: - ✅ salePrice must be an object with amount and currency - ✅ Use camelCase: earnestMoney, downPayment, loanAmount

Date Fields: - ✅ Use camelCase: contractDate, closingDate, acceptanceDate - ✅ Format: YYYY-MM-DD

Commission Fields: - ✅ Use camelCase: agentId, splitPercentage, commissionAmount


Backward Compatibility

Legacy Method Names

The library provides backward compatibility aliases for users migrating from older versions:

Old Method Name New Method Name
put_buyer_to_draft() add_buyer()
put_seller_to_draft() add_seller()
put_location_to_draft() update_location_info()
put_price_and_date_to_draft() update_price_and_date_info()
update_commission_payer() add_commission_payer()
update_personal_deal() update_personal_deal_info()
update_real_title() update_title_info()

Using Backward Compatibility

from rezen import RezenClient

client = RezenClient()
transaction_id = "your-transaction-id"

# These method pairs do the same thing:

# Add buyer
client.transaction_builder.add_buyer(transaction_id, buyer_data)
client.transaction_builder.put_buyer_to_draft(transaction_id, buyer_data)

# Add seller
client.transaction_builder.add_seller(transaction_id, seller_data)
client.transaction_builder.put_seller_to_draft(transaction_id, seller_data)

# Update location
client.transaction_builder.update_location_info(transaction_id, location_data)
client.transaction_builder.put_location_to_draft(transaction_id, location_data)

# Update price and date
client.transaction_builder.update_price_and_date_info(transaction_id, price_data)
client.transaction_builder.put_price_and_date_to_draft(transaction_id, price_data)

Query & Search Operations

List Transaction Builders

Get a paginated list of transaction builders.

Parameters:

Name Type Description Default
limit int

Maximum number of results to return

required
from_offset int

Starting offset for pagination

required
yenta_id str

User ID

required
builder_type str

Type of builder ('TRANSACTION' or 'LISTING')

'TRANSACTION'

Returns:

Type Description
Dict[str, Any]

Paginated list of transaction builders

Advanced Filtering

builders = client.transaction_builder.get_transaction_builders(
    limit=20,
    from_offset=0
)

print(f"Found {len(builders)} transaction builders")
for builder in builders:
    print(f"ID: {builder['id']}, Status: {builder['status']}")
# Get builders for specific user
user_builders = client.transaction_builder.get_transaction_builders(
    limit=50,
    from_offset=0,
    yenta_id="user-uuid-here",
    builder_type="TRANSACTION"
)
# Get only listing builders
listings = client.transaction_builder.get_transaction_builders(
    limit=25,
    from_offset=0,
    builder_type="LISTING"
)

Error Handling

Enhanced Error Messages

The Transaction Builder now includes enhanced error handling that catches common mistakes before they reach the API.

New Error Types

  • InvalidFieldNameError: Catches incorrect field names (e.g., address instead of street)
  • InvalidFieldValueError: Validates field formats (e.g., state must be uppercase)
  • TransactionSequenceError: Identifies when operations are called in wrong order
  • ValidationError: General validation failures with detailed messages

Common Field Name Errors

Field Name Validation

from rezen.exceptions import InvalidFieldNameError

try:
    # Using wrong field name
    location_data = {
        "address": "123 Main St",  # ❌ Wrong! Should be 'street'
        "city": "Salt Lake City",
        "state": "UTAH",
        "zipCode": "84101"  # ❌ Wrong! Should be 'zip'
    }
    client.transaction_builder.update_location_info(transaction_id, location_data)
except InvalidFieldNameError as e:
    print(f"Field name error: {e}")
    print(f"Use '{e.correct_name}' instead of '{e.field_name}'")

Field Value Validation

Field Value Validation

from rezen.exceptions import InvalidFieldValueError

try:
    # Wrong state format
    location_data = {
        "street": "123 Main St",
        "city": "Salt Lake City",
        "state": "utah",  # ❌ Wrong! Must be uppercase
        "zip": "84101"
    }
    client.transaction_builder.update_location_info(transaction_id, location_data)
except InvalidFieldValueError as e:
    print(f"Invalid value for '{e.field_name}': {e.value}")
    print(f"Expected: {e.expected_format}")

Transaction Sequence Errors

Sequence Requirements

The owner agent endpoint requires specific setup steps in order:

from rezen.exceptions import TransactionSequenceError

try:
    # Trying to add owner agent without proper setup
    client.transaction_builder.update_owner_agent_info(builder_id, owner_data)
except TransactionSequenceError as e:
    print(f"Sequence error: {e}")
    # Error message includes required steps:
    # 1. Create transaction (create_transaction_builder)
    # 2. Add location info (update_location_info) - REQUIRED FIRST
    # 3. Add price/date info (update_price_and_date_info) - REQUIRED SECOND
    # 4. Add buyers/sellers (add_buyer/add_seller) - REQUIRED THIRD
    # 5. THEN add owner agent (update_owner_agent_info)

Price Structure Validation

Price Field Validation

from rezen.exceptions import InvalidFieldValueError, ValidationError

try:
    price_data = {
        "dealType": "COMPENSATING",
        "propertyType": "RESIDENTIAL",
        "salePrice": 500000,  # ❌ Wrong! Must be object
        "representationType": "BUYERS_AGENT"  # ❌ Wrong! Should be 'BUYER'
    }
    client.transaction_builder.update_price_and_date_info(transaction_id, price_data)
except InvalidFieldValueError as e:
    # Catches: "Invalid value for 'salePrice': 500000. 
    # Expected: Object with 'amount' and 'currency' fields"
    print(f"Error: {e}")
except ValidationError as e:
    # Catches missing required fields
    print(f"Validation error: {e}")

Best Practices

Error Handling Best Practices

  • Catch Specific Exceptions: Use specific exception types for better error handling
  • Check Field Names: The enhanced validation catches common camelCase vs snake_case errors
  • Validate Before Submission: Required fields are now validated before API calls
  • Follow Sequence Requirements: Especially important for owner agent endpoints
  • Use Error Details: Exception objects contain helpful properties like field_name and correct_name

Complete Workflow Example

End-to-End Transaction Creation

from rezen import RezenClient
from rezen.exceptions import RezenError
import logging

def create_complete_transaction():
    """Create a complete transaction with all participants and details."""

    try:
        client = RezenClient()

        # Step 1: Create transaction builder
        print("Creating transaction builder...")
        response = client.transaction_builder.create_transaction_builder()
        transaction_id = response['id']
        print(f"✅ Created transaction: {transaction_id}")

        # Step 2: Add buyer
        print("Adding buyer...")
        buyer_data = {
            "firstName": "John",  # Use camelCase
            "lastName": "Doe",  # Use camelCase
            "email": "john.doe@email.com",
            "phoneNumber": "+1-555-123-4567"  # Use camelCase
        }
        client.transaction_builder.add_buyer(transaction_id, buyer_data)
        print("✅ Added buyer")

        # Step 3: Add seller
        print("Adding seller...")
        seller_data = {
            "firstName": "Jane",  # Use camelCase
            "lastName": "Smith",  # Use camelCase
            "email": "jane.smith@email.com",
            "phoneNumber": "+1-555-987-6543"  # Use camelCase
        }
        client.transaction_builder.add_seller(transaction_id, seller_data)
        print("✅ Added seller")

        # Step 4: Add property location
        print("Setting property location...")
        location_data = {
            "street": "123 Dream House Lane",  # Use 'street' not 'address'
            "street2": "",
            "city": "Salt Lake City",
            "state": "UTAH",  # Must be UTAH (all caps)
            "zip": "84101",  # Use 'zip' not 'zipCode'
            "county": "Salt Lake",
            "unit": "",
            "yearBuilt": 2020,  # Use camelCase
            "mlsNumber": "MLS123456",  # Use camelCase
            "escrowNumber": ""
        }
        client.transaction_builder.update_location_info(transaction_id, location_data)
        print("✅ Set property location")

        # Step 5: Set pricing and dates
        print("Setting pricing and dates...")
        price_data = {
            "salePrice": {  # Use camelCase and object structure
                "amount": 850000,
                "currency": "USD"
            },
            "earnestMoney": 17000,  # Use camelCase
            "acceptanceDate": "2024-02-01",  # Use camelCase
            "closingDate": "2024-03-15"  # Use camelCase
        }
        client.transaction_builder.update_price_and_date_info(transaction_id, price_data)
        print("✅ Set pricing and dates")

        # Step 6: Add service providers
        print("Adding service providers...")
        inspector_data = {
            "type": "INSPECTOR",
            "firstName": "Mike",  # Use camelCase
            "lastName": "Inspector",  # Use camelCase
            "company": "Quality Inspections Inc",
            "phoneNumber": "+1-555-INSPECT",  # Use camelCase
            "email": "mike@qualityinspections.com"
        }
        client.transaction_builder.add_participant(transaction_id, inspector_data)
        print("✅ Added inspector")

        # Step 7: Submit transaction
        print("Submitting transaction...")
        submit_response = client.transaction_builder.submit_transaction(transaction_id)
        print("✅ Transaction submitted successfully!")

        return {
            "success": True,
            "transaction_id": transaction_id,
            "submit_response": submit_response
        }

    except RezenError as e:
        logging.error(f"ReZEN API error: {e}")
        return {
            "success": False,
            "error": str(e),
            "transaction_id": transaction_id if 'transaction_id' in locals() else None
        }
    except Exception as e:
        logging.error(f"Unexpected error: {e}")
        return {
            "success": False,
            "error": str(e)
        }

# Run the example
result = create_complete_transaction()
if result["success"]:
    print(f"🎉 Transaction {result['transaction_id']} created successfully!")
else:
    print(f"❌ Failed to create transaction: {result['error']}")

Next Steps