# Trigger a new soft credit pull for a merchant. Idempotent: if a successful or pending soft pull already exists, returns HTTP 200 with alreadyExisted=true.
If a new pull is triggered, returns HTTP 202 with alreadyExisted=false.

## Trigger Soft Credit Pull

Initiates a new soft credit pull for a merchant through Experian. This endpoint is idempotent: if a successful or pending soft pull already exists for the merchant, it returns HTTP 200 with `alreadyExisted=true` without triggering a new pull. If no valid pull exists, it triggers a new one and returns HTTP 202 with `alreadyExisted=false`.

### Endpoint

`POST /api/v1/merchant/creditProfile/softPull`

### Authentication

Basic HTTP Authentication required. Encode `username:password` in Base64 and pass in the Authorization header:

```
Authorization: Basic {base64(username:password)}
```

### When to use

Call this endpoint at the start of the underwriting process to initiate Experian verification for a merchant. After triggering the pull, poll `GET /creditProfile` until the report status changes to `Completed`, then download the report via `GET /creditProfile/report`. The idempotency behavior means it is safe to call multiple times without creating duplicate pulls.

### Request Body

| Field             | Type            | Required | Description                                  |
| ----------------- | --------------- | -------- | -------------------------------------------- |
| merchantProfileId | integer (int32) | Yes      | Merchant profile ID to run the soft pull for |

```json
{
  "merchantProfileId": 161787
}
```

### Response

**200 OK** — soft pull already existed (no new pull triggered)

**202 Accepted** — new soft pull triggered successfully

| Field               | Type    | Description                                                             |
| ------------------- | ------- | ----------------------------------------------------------------------- |
| data.reportId       | string  | ID of the soft pull report — use with GET /creditProfile/report         |
| data.status         | string  | Current status: `Pending`, `Completed`, `Failed`                        |
| data.alreadyExisted | boolean | `true` if existing pull was returned, `false` if new pull was triggered |
| requestId           | integer | Unique request identifier for tracing                                   |
| success             | boolean | `true` if request succeeded                                             |
| error               | string  | Error message if `success` is `false`                                   |

```json
{
  "data": {
    "reportId": "rpt-8f3a2c1d",
    "status": "Pending",
    "alreadyExisted": false
  },
  "requestId": 4188102,
  "success": true,
  "error": null
}
```

**When pull already existed (HTTP 200):**

```json
{
  "data": {
    "reportId": "rpt-8f3a2c1d",
    "status": "Completed",
    "alreadyExisted": true
  },
  "requestId": 4188103,
  "success": true,
  "error": null
}
```

### Error Codes

| Code | When it happens                                       |
| ---- | ----------------------------------------------------- |
| 400  | `merchantProfileId` missing or invalid                |
| 401  | Invalid or missing Basic Auth credentials             |
| 403  | User does not have Underwriting access                |
| 404  | Merchant profile not found                            |
| 500  | Internal server error or Experian service unavailable |

### Common Mistakes

* Treating HTTP 200 and 202 as errors — both are success responses. 200 means idempotent return, 202 means new pull started.
* Not waiting for `status: Completed` before downloading the report — the pull is asynchronous. Poll `GET /creditProfile` until reports show `Completed` status.
* Calling this endpoint repeatedly expecting multiple pulls — by design, it returns the existing pull if one is active or completed.

### Related Endpoints

* [`GET /api/v1/merchant/creditProfile`](./creditprofile_getcreditprofile.md) — check pull status and get reportId after triggering
* [`GET /api/v1/merchant/creditProfile/report`](./creditprofile_getcreditprofilereport.md) — download completed report content

### Example

```bash
curl -X POST "https://hq.staging.netevia.dev/api/v1/merchant/creditProfile/softPull" \
  -H "Authorization: Basic $(echo -n 'username:password' | base64)" \
  -H "Content-Type: application/json" \
  -d '{"merchantProfileId": 161787}'
```

# OpenAPI definition

```json
{
  "openapi": "3.0.0",
  "info": {
    "version": "v1",
    "title": "Netevia HQ | API Documentation",
    "description": "Netevia HQ | API Documentation"
  },
  "paths": {
    "/api/v1/merchant/creditProfile/softPull": {
      "post": {
        "tags": [
          "Underwriting"
        ],
        "summary": "Trigger a new soft credit pull for a merchant. Idempotent: if a successful or pending soft pull already exists, returns HTTP 200 with alreadyExisted=true.\r\nIf a new pull is triggered, returns HTTP 202 with alreadyExisted=false.",
        "operationId": "CreditProfile_TriggerSoftPull",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SoftPullRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SoftPullRequest"
              }
            },
            "application/xml": {
              "schema": {
                "$ref": "#/components/schemas/SoftPullRequest"
              }
            },
            "text/xml": {
              "schema": {
                "$ref": "#/components/schemas/SoftPullRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/SoftPullRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              },
              "text/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              },
              "text/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResult1_SoftPullResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "Basic": []
    }
  ],
  "servers": [
    {
      "url": "https://hq.staging.netevia.dev"
    }
  ],
  "components": {
    "securitySchemes": {
      "Basic": {
        "type": "http",
        "description": "Basic HTTP Authentication",
        "scheme": "basic"
      }
    },
    "schemas": {
      "ValidationError": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string"
          },
          "error": {
            "type": "string"
          }
        }
      },
      "SoftPullRequest": {
        "required": [
          "merchantProfileId"
        ],
        "type": "object",
        "properties": {
          "merchantProfileId": {
            "format": "int32",
            "type": "integer"
          }
        }
      },
      "ApiResult1_SoftPullResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SoftPullResponse"
          },
          "requestId": {
            "format": "int32",
            "type": "integer"
          },
          "success": {
            "type": "boolean"
          },
          "error": {
            "type": "string"
          },
          "validationErrors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            }
          }
        }
      },
      "SoftPullResponse": {
        "type": "object",
        "properties": {
          "reportId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "alreadyExisted": {
            "type": "boolean"
          }
        }
      }
    }
  }
}
```