> 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/quickstart.md).

# Quickstart

Get an API key, point at the right host, and create your first placement.

## 1. Get an API key

Keys are `ca_<prefix>_<secret>` — for example `ca_a3f8c0d1_qY8…`. The middle segment is the public key ID (safe to quote in a support thread); the rest is a secret we store only as a bcrypt hash.

Two issuance paths, both returning the plaintext **exactly once**:

* **Self-serve.** The onboarding wizard walks your account from signup through KYB, a remittance bank link and MSA acceptance. `POST /v1/creditors/me/issue-api-key` mints the key once that gate clears.
* **Operator-provisioned.** An admin mints it on approval.

An issued key can never be re-displayed — not in the dashboard, not by support. `GET /v1/settings` returns a masked rendering so you can confirm *which* key an account holds; the bullets are a display artifact, not a credential. **Rotation is the only recovery path.**

Rotate with `POST /v1/settings/api-key/rotate`. That route needs a dashboard session and refuses `ca_*` bearers with `403` — deliberately, so a stolen key cannot mint its own replacement and lock you out. Rotation takes effect immediately with no grace period, so coordinate it with your deploy.

{% hint style="warning" %}
A key belonging to an account that is not `verified` is refused with `403 Account not active`, even though the key itself is valid.
{% endhint %}

## 2. Point at the right host

All routes are versioned under `/v1`. There is no production default — you select a host explicitly.

| Environment | Base URL                                | API root                                   |
| ----------- | --------------------------------------- | ------------------------------------------ |
| Production  | `https://api.moderncollections.io`      | `https://api.moderncollections.io/v1`      |
| Demo        | `https://app.demo.moderncollections.io` | `https://app.demo.moderncollections.io/v1` |

Keys and webhook signing secrets are issued per environment and do not work across them.

{% hint style="info" %}
On demo, the bare host — including `/health` — is the dashboard origin, not the API. Point reachability checks at a `/v1/*` route instead.
{% endhint %}

## 3. Make a call

```bash
export MC_API_BASE="https://api.moderncollections.io/v1"
# MC_API_KEY from your secret manager — never commit it.

curl -X POST "$MC_API_BASE/placements" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "invoice_number": "INV-2026-0042",
    "invoice_amount": 7500.00,
    "invoice_date": "2026-04-01",
    "due_date": "2026-05-01",
    "debtor": {
      "company_name": "Acme Inc.",
      "primary_email": "ap@acme.example",
      "primary_phone": "+15105550101",
      "state": "TX"
    }
  }'
```

`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",
  "warnings": []
}
```

Required fields are `invoice_number`, `invoice_amount` (positive decimal), `invoice_date`, `due_date` and `debtor.company_name`. `debtor.state` is strongly recommended — it drives quiet hours and the state rules the compliance engine evaluates — and is **required** under a partner scope. Full request and response shapes are in the [OpenAPI spec](https://github.com/knollmeyersam-dot/MC-Docs/tree/main/api-reference/rest-api/openapi.yaml).

Two responses that are not `201`:

* **`202`** with `{"intake_review_id", "status": "pending_review", "reason": "sol_time_barred"}` — the debtor state's statute of limitations would bar collection, so the submission went to operator review. The identifier is a review ID, **not** a placement ID; do not poll it as one.
* **`409`** **`duplicate_invoice`** — that invoice number already exists for this creditor. The body is `{"detail": {"reason": "duplicate_invoice", "message": ..., "invoice_number": ..., "placement_id": ...}}`. `placement_id` is the placement already holding the number, so a retry after a timeout or a dropped connection reconciles from the refusal itself. Match on `detail.reason`, not on the message. There is no `Idempotency-Key` on placement creation; a stable `invoice_number` plus that `placement_id` is what makes re-runs safe.

A non-empty `warnings` on a `201` means the placement was created but not exactly as submitted — log it.

## 4. Follow the work

```bash
curl "$MC_API_BASE/placements/$PLACEMENT_ID" -H "Authorization: Bearer $MC_API_KEY"
```

An eligible placement moves `pending_enrichment → ready → in_outreach`. `estimated_first_contact` is `created_at` plus the enrichment SLA (15 minutes by default) — an estimate, not a guarantee. Verification, compliance holds and scheduling all gate real outreach.

[Register a webhook](/webhooks/receiving.md) rather than polling. See [Placements](/rest-api/placement-lifecycle.md) for what the status, `compliance` and `pause` fields mean.

## First-call gotchas

| Symptom                            | Cause                                                                                                     |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `401 Invalid API key`              | Malformed `ca_<prefix>_<secret>`, revoked key, or the wrong environment.                                  |
| `401 Missing authorization header` | No `Authorization` header at all.                                                                         |
| `403 Account not active`           | The creditor account is not `verified`.                                                                   |
| `422` with a list-shaped `detail`  | Request validation. `invoice_amount` must be positive; `debtor.company_name` is required.                 |
| `409` `duplicate_invoice`          | Reuse of an existing `invoice_number`. The body carries `placement_id`, the placement already holding it. |
| Stuck in `pending_enrichment`      | Enrichment is still running — compare against `estimated_first_contact`.                                  |

## Next

* [Errors and limits](/getting-started/errors.md) — retries, idempotency, rate limits.
* [Webhooks](/webhooks/receiving.md) — events instead of polling.
* [Ingest overdue invoices](/guides/ingest-invoices.md) — the full batch loop.
* [Clients and MCP](/clients/clients.md) — Python client, CLI, agent tools.


---

# 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/quickstart.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.
