> 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 to support; the rest is a secret we store only as a hash.

* Self-serve: the onboarding wizard (signup, KYB, a payout bank link, MSA acceptance), then `POST /v1/creditors/me/issue-api-key`.
* Operator-provisioned: an admin mints it on approval.

The plaintext is shown exactly once. `GET /v1/settings` returns a masked rendering to confirm which key an account holds. Rotation is the only recovery path: `POST /v1/settings/api-key/rotate` needs a dashboard session (a `ca_*` bearer gets `403`). The old key works for 24 hours (`previous_key_expires_at`); `{"expire_previous_now": true}` revokes it at once.

{% 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 under `/v1`. There is no default host; you select one explicitly.

| Environment | API root                                   | Dashboard                               |
| ----------- | ------------------------------------------ | --------------------------------------- |
| Production  | `https://api.moderncollections.io/v1`      | `https://app.moderncollections.io`      |
| Sandbox     | `https://api.demo.moderncollections.io/v1` | `https://app.demo.moderncollections.io` |

A production placement is real collection work. The sandbox runs the same API, dashboard and MCP server; nothing in it reaches a real person or moves money. It needs its own sign-up and its own keys (a production key does not work there), verifies the account automatically, simulates calls and captures emails, delivers webhooks to the URLs you configure, and runs the outreach clock 144 times faster. Each sandbox creditor holds at most 25 invoices (`422 demo_placement_limit`).

## 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",
  "outreach_note": "We review each new placement before outreach starts.",
  "created_at": "2026-05-12T10:30:00Z",
  "warnings": []
}
```

Required: `invoice_number`, `invoice_amount` (positive decimal), `invoice_date`, `due_date`, `debtor.company_name`. `debtor.state` drives quiet hours and the state rules (a `debtor.zip` resolving to one state is accepted instead). Under a partner scope, an invoice with no usable state is held until a person enters it. Full shapes are in the [OpenAPI spec](https://github.com/knollmeyersam-dot/MC-Docs/tree/main/api-reference/rest-api/openapi.yaml).

| Response                                                                                      | Meaning                                                                                                                                                                           |
| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `201` with non-empty `warnings`                                                               | Created, but not exactly as submitted. Log it                                                                                                                                     |
| `202` `{"intake_review_id", "status": "pending_review", "reason": "sol_time_barred"}`         | The debtor state's statute of limitations would bar collection; sent to operator review. The id is a review id, not a placement id                                                |
| `202` `{"intake_review_id", "status": "pending_review", "reason": "missing_required_fields"}` | Under a partner scope, no usable debtor state. Held until a person enters it, then placed. The id is a review id, not a placement id                                              |
| `409` `duplicate_invoice`                                                                     | That invoice number exists for this creditor. `detail.placement_id` is the placement holding it, so a retry after a timeout reconciles from the refusal. Match on `detail.reason` |

A stable `invoice_number` is what makes re-runs safe. To key retries on your own id instead, send an `Idempotency-Key` ([Idempotency](/getting-started/errors.md#idempotency)).

## 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`. We review each new placement before outreach starts; `outreach_note` and `pause` say what it waits for. [Register a webhook](/webhooks/receiving.md) rather than polling. See [Placements](/rest-api/placement-lifecycle.md) for the status and `pause` fields.

## 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. Read `pause` on `GET /v1/placements/{id}` for what the placement waits for.  |

## 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
* [CLI](/clients/cli.md), [MCP](/clients/mcp.md), [Python](/clients/clients.md)
* [Upload files](/rest-api/documents.md): contracts, invoices and supporting evidence


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.moderncollections.io/getting-started/quickstart.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
