> For the complete documentation index, see [llms.txt](https://docs.moderncollections.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.moderncollections.io/getting-started/first-api-call.md).

# First API call

This page assumes you have:

1. A creditor API key issued by an admin — see [Authentication](/getting-started/authentication.md).
2. The base URL for your provisioned environment.
3. A reachable webhook endpoint, **or** you're OK skipping webhooks for the first call.

We'll create a placement, watch it move into outreach, and inspect the result.

## What you'll do

```
1. POST /v1/placements         → create a placement for a test debtor
2. GET  /v1/placements/{id}    → poll status as enrichment runs
3. GET  /v1/placements/{id}/calls → inspect the first call once outreach starts
```

On the `demo` environment, seeded scenarios let you exercise the full outreach lifecycle without waiting out the multi-day cadence. See [Environments](/getting-started/environments.md).

## Step 1 — create a placement

{% tabs %}
{% tab title="curl" %}

```bash
curl -X POST https://<api-host>/v1/placements \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "invoice_number": "INV-TEST-001",
    "invoice_amount": 7500.00,
    "currency": "USD",
    "invoice_date": "2025-11-01",
    "due_date": "2025-12-01",
    "posture": "preserve",
    "debtor": {
      "company_name": "Acme Test Corp",
      "primary_domain": "acmetest.example",
      "primary_email": "ap@acmetest.example",
      "primary_phone": "+15105550101",
      "state": "TX",
      "city": "Austin",
      "zip": "78701"
    },
    "notes": "First-integration smoke test"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import os, httpx

client = httpx.Client(
    base_url=os.environ["MC_API_BASE"],
    headers={"Authorization": f"Bearer {os.environ['MC_API_KEY']}"},
)

payload = {
    "invoice_number": "INV-TEST-001",
    "invoice_amount": 7500.00,
    "currency": "USD",
    "invoice_date": "2025-11-01",
    "due_date": "2025-12-01",
    "posture": "preserve",
    "debtor": {
        "company_name": "Acme Test Corp",
        "primary_domain": "acmetest.example",
        "primary_email": "ap@acmetest.example",
        "primary_phone": "+15105550101",
        "state": "TX",
        "city": "Austin",
        "zip": "78701",
    },
    "notes": "First-integration smoke test",
}

response = client.post("/placements", json=payload)
response.raise_for_status()
placement = response.json()
print(placement["placement_id"], placement["status"])
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const response = await fetch(
  `${process.env.MC_API_BASE}/placements`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MC_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      invoice_number: "INV-TEST-001",
      invoice_amount: 7500.0,
      currency: "USD",
      invoice_date: "2025-11-01",
      due_date: "2025-12-01",
      posture: "preserve",
      debtor: {
        company_name: "Acme Test Corp",
        primary_domain: "acmetest.example",
        primary_email: "ap@acmetest.example",
        primary_phone: "+15105550101",
        state: "TX",
        city: "Austin",
        zip: "78701",
      },
      notes: "First-integration smoke test",
    }),
  },
);
const placement = await response.json();
console.log(placement.placement_id, placement.status);
```

{% endtab %}
{% endtabs %}

**Expected response — `201 Created`:**

```json
{
  "placement_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending_enrichment",
  "debtor_id": "660e8400-e29b-41d4-a716-446655440001",
  "estimated_first_contact": "2026-05-12T10:45:00Z",
  "created_at": "2026-05-12T10:30:00Z"
}
```

Save the `placement_id` for the next step.

**Special case — time-barred submissions return `202`** with `{"intake_review_id": "...", "status": "pending_review", "reason": "sol_time_barred"}` instead of minting a placement. These are routed to operator adjudication.

## Step 2 — poll for status

The placement starts in `pending_enrichment` and progresses through subsequent statuses (`ready`, `in_outreach`, etc.). The detail endpoint includes a `timeline` array built from audit events.

```bash
curl https://<api-host>/v1/placements/$PLACEMENT_ID \
  -H "Authorization: Bearer $MC_API_KEY"
```

```
pending_enrichment → ready → in_outreach
```

Possible status values today: `pending_enrichment`, `ready`, `in_outreach`, `disputed`, `pending_payment`, `paid`, `closed_uncollected`, `recalled`, `needs_review`, `resolved`, `resolved_out_of_band`, `withdrawn_by_creditor`.

## Step 3 — inspect the first call

Once the placement reaches `in_outreach`, the first call is scheduled and executed. Fetch the calls collection:

```bash
curl https://<api-host>/v1/placements/$PLACEMENT_ID/calls \
  -H "Authorization: Bearer $MC_API_KEY"
```

You'll see one call per attempt, each with `status`, `outcome`, `duration_seconds`, `transcript`, `ai_summary`, and `recording_url`.

## What next?

* [Webhooks overview](/webhooks/overview.md) — get notified instead of polling.
* [Ingest overdue invoices](/integration-guides/ingest-overdue-invoices.md) — the recommended batch flow.
* [Error handling](/getting-started/error-handling.md) — what to do when something fails.

## Common gotchas on the first call

| Symptom                                             | Likely cause                                                                                                                                                             |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `401 Invalid API key`                               | Key prefix or secret malformed, key revoked, or wrong environment. Check the `ca_<prefix>_<secret>` shape.                                                               |
| `401 Missing authorization header`                  | Bearer header missing entirely.                                                                                                                                          |
| `403 Account not active`                            | Creditor account is not in `verified` status (still `pending_*`, or `suspended`/`rejected`).                                                                             |
| `422` validation error                              | `invoice_amount` must be positive; `debtor.company_name` is required. The API returns a list-shaped `detail` (see [Error handling](/getting-started/error-handling.md)). |
| `409 Duplicate invoice: ...`                        | Same `invoice_number` already exists for this creditor. Use a unique value.                                                                                              |
| `202 pending_review` with `reason: sol_time_barred` | The debtor's state's statute of limitations would bar collection — submission queued for operator review.                                                                |
| Placement stuck in `pending_enrichment`             | Enrichment is still running. Check `estimated_first_contact` against `enrichment_sla_minutes` (default 15).                                                              |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.moderncollections.io/getting-started/first-api-call.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
