---
title: "Create Placement"
method: POST
path: "/api/external/v2/placements"
tags: ["external-v2-placements"]
---

# Create Placement

`POST /api/external/v2/placements`

Create a new placement (lender outreach) on a deal.

Required body fields: ``deal_id`` and ``private_company_id``.  Both must
belong to the caller's account; cross-account or non-existent IDs return
404.  AI lender-contact matching is disabled for this endpoint
(``match_contact_with_ai=False``) — placements created via the external
API are explicit and deterministic.

## Request body

- CreatePlacementRequest — POST /api/external/v2/placements request body. Creates a new placement — a record of lender outreach on a deal. ``deal_id`` identifies the target deal and ``private_company_id`` identifies the lender (a PrivateCompany). Both must belong to the caller's account; cross-account IDs return 404. Status defaults to ``new`` server-side when omitted; visibility falls back to the model default (``hidden``) unless the deal-owner-account rules force ``shared`` (customer accounts; see ``PlacementsController.create_placement``).
  - `deal_id` integer, required — ID of the deal this placement belongs to (required).
  - `private_company_id` integer, required — ID of the lender company (a PrivateCompany) being placed against this deal. Must belong to the caller's account (use list_companies to find candidates).
  - `contact_id` integer, nullable — Optional ID of the lender contact (a Contact in the caller's account) for this outreach.
  - `status` 'new' | 'sent' | 'lender_reviewing' | 'terms_received' | 'term_sheet_received' | 'executed_ts_in_closing' | 'closed' | 'unresponsive' | 'willing_to_negotiate' | 'lender_passed' | 'archived'
  - `visibility` 'hidden' | 'masked' | 'shared'
  - `description` string, nullable — Free-text description / per-lender note. This is the canonical location for lender-specific feedback on the deal (e.g. '08/11 soft quote received…').
  - `score` number, nullable — Manual relevance score (0-100).
  - `outreach_date` string, date-time, nullable — Timestamp the lender was first reached out to (ISO 8601).
  - `lender_status` 'origination' | 'new' | 'lead_qualification' | 'quotation' | 'negotiation' | 'offer' | 'term_sheet' | 'good_faith_deposit' | 'diligence' | 'in_closing' | 'closed' | 'archived'

## Response `201`

Successful Response

- PlacementObjectResponse — OpenAPI schema for GET /api/external/v2/placements/<id> (object envelope).
  - `request_id` string, required
  - `timestamp` string, required
  - `data` PlacementResponse, required
    - `id` integer, required
    - `deal_id` integer, required
    - `contact_id` integer, nullable
    - `private_company_id` integer, nullable
    - `lender_name` string, nullable — Lender display name for this placement — the account's own CRM / address-book name for the lender, falling back to the canonical lender (Organization) name when the CRM record is unnamed. Null when no lender is set. Embedded so callers need not resolve private_company_id via a separate lookup. For non-owner viewers of masked placements, this is a stable masked label such as 'Lender A'.
    - `contact_name` string, nullable — Full name of the lender contact on this placement. Null when no contact is set, or when a non-owner viewer is reading a masked placement.
    - `status` string, nullable
    - `visibility` string, nullable
    - `lender_status` string, nullable
    - `description` string, nullable
    - `score` number, nullable
    - `lev_score` number, nullable
    - `outreach_source` string, nullable
    - `outreach_date` string, nullable
    - `lender_first_response_date` string, nullable
    - `last_communication_date` string, nullable
    - `created_at` string, nullable
    - `updated_at` string, nullable

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/lev/apis/lev-api.md) · [All operations](https://skmtc.net/lev/apis/lev-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/lev/lev-api/revisions/e1915e1423cf/schema)
