> ## Documentation Index
> Fetch the complete documentation index at: https://docs.herondata.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Broker Submissions API

> Send complete funding submissions directly to funders using our Broker Submissions API

The Broker Submissions API allows brokers to programmatically submit applications with company details and supporting documents directly to a funder.

## Prerequisites

Before following this guide, you will need:

* A broker email address associated with your organization
* Access to generate API keys (requires funder authentication)

## Steps

### 1. Create a Broker Submission

Create a new submission with a name ([API reference](https://docs.herondata.io/api-reference/brokersubmissions/create-broker-submission)):

```python app.py theme={null}
BROKER_API_KEY = "bft_xxxxxxxxx"
BASE_URL = "https://app.herondata.io"

response = requests.post(
  f"{BASE_URL}/api/broker_submissions/",
  headers={
    "x-api-key": BROKER_API_KEY,
    "Content-Type": "application/json",
  },
  json={
    "name": "ABC Company - Working Capital Request"
  }
)

response.raise_for_status()

data = response.json()
# ^ { "heron_id": "sub_xxxxxxxxx" }

submission_heron_id = data["heron_id"]
```

<Note>
  The submission name must be at least 10 characters long and is used for reference purposes to help identify the submission.
</Note>

The returned submission Heron ID will be used to upload files and company details, linking them to a unique ID.

### 2. Add Company and Owner Details

Update the submission with detailed business and owner information ([API reference](https://docs.herondata.io/api-reference/brokersubmissions/add-details-to-broker-submission)):

```python app.py theme={null}
BASE_URL = "https://app.herondata.io"
BROKER_API_KEY = 'bft_xxxxxxxxx'

response = requests.post(
  f"{BASE_URL}/api/broker_submissions/{submission_heron_id}/update_information",
  headers={
    "x-api-key": BROKER_API_KEY,
    "Content-Type": "application/json",
  },
  json={
    "source_email_address": "jane.broker@abcbroker.com",
    "company_legal_business_name": "ABC Company LLC",
    "company_email": "contact@abccompany.com",
    "company_phone_number": "555-123-4567",
    "federal_tax_id": "12-3456789",
    "amount_requested": 100000,
    "annual_revenue": 500000,
    "industry_type": "Restaurant",
    "business_start_date": "2018-05-15",
    "company_physical_address": {
      "line_1": "123 Main St",
      "city": "New York",
      "state": "NY",
      "zip": "10001"
    },
    "owner_1": {
      "first_name": "John",
      "last_name": "Doe",
      "email_address": "john.doe@abccompany.com",
      "mobile_phone": "555-987-6543",
      "ownership_percentage": 75,
      "date_of_birth": "1985-03-20"
    }
  }
)

response.raise_for_status()

updated_info = response.json()
# ^ The full submission record with the merged company + owner details
#   (see EndUserInformationSchema in the API reference)
```

<Note>
  Set `source_email_address` to the email of the broker who submitted the deal so they receive credit for the submission.
</Note>

All fields in the update request are optional, allowing you to provide only the information you have available.

### 3. Upload PDF Files

Upload supporting documents to the submission ([API reference](https://docs.herondata.io/api-reference/brokersubmissions/upload-pdf-files-for-broker-submission)). Optionally include a `file_class` form field to apply that classification to all files in the request — if omitted, Heron will automatically classify each file based on its contents:

```python app.py theme={null}
BASE_URL = "https://app.herondata.io"
BROKER_API_KEY = 'bft_xxxxxxxxx'

files = [
  ('files', ('statement_q4.pdf', open('statement_q4.pdf', 'rb'), 'application/pdf')),
  ('files', ('statement_q3.pdf', open('statement_q3.pdf', 'rb'), 'application/pdf'))
]

response = requests.post(
  f"{BASE_URL}/api/broker_submissions/{submission_heron_id}/files",
  headers={
    "x-api-key": BROKER_API_KEY,
  },
  data={"file_class": "bank_statement"},  # optional — applies to all files in this request
  files=files
)

response.raise_for_status()

upload_results = response.json()
# ^ [
#     { "file": "statement_q4.pdf", "status": "uploaded" },
#     { "file": "statement_q3.pdf", "status": "uploaded" }
#   ]
```

<Note>
  Because `file_class` applies to every file in the request, uploads with files of different classes must be split into separate requests (one per class). Alternatively, omit `file_class` and let Heron classify each file automatically.
</Note>

## Response Status Codes

The file upload endpoint returns different status codes based on the outcome:

* **201**: All files uploaded successfully
* **207**: Partial success - some files uploaded, others failed
* **400**: All files failed validation or upload

For partial failures (207), the response will include details about which files succeeded and which failed:

```json theme={null}
[
  {
    "file": "statement.pdf",
    "status": "uploaded"
  },
  {
    "file": "invalid.pdf",
    "status": "error",
    "reason": "File type application/msword not allowed. Allowed: application/pdf"
  }
]
```

## File Restrictions

When uploading files:

* Only PDF files are accepted
* Duplicate files for the same submission will be rejected
