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

# Upload

> EcoMail Hub users upload CSV files to create creditor profile records.

## Real-World Example

Maya receives a CSV of 800 creditor prospects. She uploads it in Import Creditor Profiles. The portal checks the headers first, shows which required headers are present, stores the file, creates upload history, and queues the import.

If 780 rows are valid and 20 rows have duplicate or invalid data, the valid profiles should still be created and the failed rows should be available in a failed CSV.

## Visual Flow

```mermaid placement="top-right" actions={true} theme={"system"}
flowchart TD
    A["User selects creditor profile CSV"] --> B["Portal reads and checks headers"]
    B --> C{"Required headers present?"}
    C -->|No| D["Block submit and show missing headers"]
    C -->|Yes| E["Store file in import_creditor_profiles"]
    E --> F["Create queued upload history"]
    F --> G["Dispatch import job on imports queue"]
    G --> H["Create profiles and contacts row by row"]
    H --> I["Email import summary to EcoMail Hub user"]
    classDef default fill:#F8FAFC,stroke:#64748B,stroke-width:1.5px,color:#0F172A;
    classDef actor fill:#E0F2FE,stroke:#0284C7,stroke-width:2px,color:#0C4A6E;
    classDef system fill:#F8FAFC,stroke:#64748B,stroke-width:1.5px,color:#0F172A;
    classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F;
    classDef risk fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,color:#7F1D1D;
    classDef outcome fill:#DCFCE7,stroke:#16A34A,stroke-width:2px,color:#14532D;
    class A actor;
    class B,E,F,G,H system;
    class I outcome;
    class C decision;
    class D risk;
    linkStyle default stroke:#94A3B8,stroke-width:2px;
```

## Required CSV Fields

The upload expects the creditor profile headers defined by the app, including company name, address, city, state, zip, phone, URL, company email, and optional contact fields for up to three contacts.

## How It Should Work

* It should allow downloading a sample CSV with the expected headers and example creditor profile rows.
* It should accept CSV uploads only.
* It should normalize headers and detect required headers before submitting.
* It should store the uploaded file and create an import history record.
* It should process rows in a queued job, not inside the browser request.
* It should create contacts only when contact first and last name are present.
* It should email the EcoMail Hub user when the import completes, including total, successful, and failed record counts.

## How It Should Not Work

* It should not import files with missing required headers.
* It should not create duplicate profiles for the same company name, city, and state.
* It should not stop the entire import because one row is invalid.
* It should not create creditor consumer accounts; this import is only for creditor profiles.

## Developer Notes

* The sample CSV API is `GET /import-creditor-profiles/sample-csv`.
* Import history starts as `Queued`, moves to `In-Progress`, then becomes `Completed` or `Failed`.
* Failed rows are written to a failed CSV with an `Errors` column.
* The job runs on the `imports` queue.
* Completion emails are queued on the mail queue after the job marks the upload history as completed.

## Related App Areas

* `app/Http/Controllers/Ecomailhub/ImportCreditorProfileController.php`
* `app/Services/Ecomailhub/ImportCreditorProfileService.php`
* `app/Jobs/ImportCreditorProfilesJob.php`
* `app/Enums/CreditorProfileImportField.php`
* `app/Mail/Ecomailhub/CreditorProfileImportCompletedMail.php`
