> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moneyline.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Create a submission, upload a bank statement, and read the analytics — in about five minutes, in the language of your choice.

## Install

```bash npm icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/typescript.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=cba1e12257cdbf42b6c7a23031def04f" theme={null}
npm install @moneyline/sdk
```

```bash pip icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/python.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=a9a026d5d8b16735c0cea1b7dd0ac6e5" theme={null}
pip install moneyline
```

```bash go icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/go.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=338b141516fd81c7c6c2302fdf1e318b" theme={null}
go get github.com/paragonhq/moneylined/sdks/go
```

## Base URL

| Environment | Base URL |
| - | - |
| Local (self-hosted, default) | `http://localhost:3000` |
| Production | `https://api.moneyline.co` |

Every example below runs against `http://localhost:3000`. See [self-hosting](https://docs.moneyline.co/guides/self-hosting.md) to bring that up, or swap in your production URL.

## Authenticate

Every request needs an API key, sent as either `Authorization: Bearer <key>` or `X-Api-Key: <key>`. Keys are `ml_live_*` (production) or `ml_test_*` (sandbox).

```bash theme={null}
export MONEYLINE_API_KEY="ml_test_your_api_key_here"
```

All three SDKs read `MONEYLINE_API_KEY` from the environment, so you rarely pass the key in code:

```ts TypeScript icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/typescript.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=cba1e12257cdbf42b6c7a23031def04f" theme={null}
import { Moneyline } from '@moneyline/sdk';

// Reads MONEYLINE_API_KEY and MONEYLINE_BASE_URL from the environment.
const client = new Moneyline();
```

```python Python icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/python.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=a9a026d5d8b16735c0cea1b7dd0ac6e5" theme={null}
from moneyline import Moneyline

client = Moneyline()
```

```go Go icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/go.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=338b141516fd81c7c6c2302fdf1e318b" theme={null}
client, err := moneyline.NewClient("")
if err != nil {
	log.Fatal(err)
}
ctx := context.Background()
```

> [!WARNING]
>
> **One naming rule worth knowing up front.** The API takes `snake_case` request
> bodies and returns `camelCase` response fields. You send `external_id`, you read
> back `externalId`. The Node and Python SDKs pass your parameters through
> verbatim, so their create and update params are snake\_case too. This trips up
> nearly everyone once.

**1. Create a submission**

A submission is the container for one applicant's documents and analysis.

```bash cURL icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/curl.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=317cbd8cd7548ad8579adf23d3bd0ec9" theme={null}
curl -X POST http://localhost:3000/v1/submissions \
  -H "Authorization: Bearer $MONEYLINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "deal-001",
    "name": "Acme Corp Application",
    "company_info": { "name": "Acme Corp", "ein": "12-3456789" }
  }'
```

```ts TypeScript icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/typescript.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=cba1e12257cdbf42b6c7a23031def04f" theme={null}
const submission = await client.submissions.create({
  external_id: 'deal-001',
  name: 'Acme Corp Application',
  company_info: { name: 'Acme Corp', ein: '12-3456789' },
});

console.log(submission.id, submission.externalId, submission.status);
```

```python Python icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/python.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=a9a026d5d8b16735c0cea1b7dd0ac6e5" theme={null}
submission = client.submissions.create(
    external_id="deal-001",
    name="Acme Corp Application",
    company_info={"name": "Acme Corp", "ein": "12-3456789"},
)

print(submission.id, submission.external_id, submission.status)
```

```go Go icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/go.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=338b141516fd81c7c6c2302fdf1e318b" theme={null}
submission, err := client.Submissions.Create(ctx, &moneyline.CreateSubmissionParams{
	ExternalID:  "deal-001",
	Name:        "Acme Corp Application",
	CompanyInfo: map[string]interface{}{"name": "Acme Corp", "ein": "12-3456789"},
})
if err != nil {
	log.Fatal(err)
}
```

The response is wrapped in a `data` envelope:

```json theme={null}
{
  "data": {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "tenantId": "9c1f0f6e-3f1a-4a5e-9d2b-7c3e1b0a4d55",
    "externalId": "deal-001",
    "name": "Acme Corp Application",
    "status": "new",
    "metadata": {},
    "companyInfo": { "name": "Acme Corp", "ein": "12-3456789" },
    "createdAt": "2026-09-02T00:00:00.000Z",
    "updatedAt": "2026-09-02T00:00:00.000Z"
  }
}
```

The SDKs unwrap `data` for you and hand back the object directly.

**2. Upload a document**

Documents are uploaded as `multipart/form-data` and classified automatically — bank statement, tax return, P\&L, and so on — then queued for parsing.

```bash cURL icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/curl.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=317cbd8cd7548ad8579adf23d3bd0ec9" theme={null}
curl -X POST http://localhost:3000/v1/submissions/$SUBMISSION_ID/documents \
  -H "Authorization: Bearer $MONEYLINE_API_KEY" \
  -F "file=@./chase-jan-2026.pdf"
```

```ts TypeScript icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/typescript.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=cba1e12257cdbf42b6c7a23031def04f" theme={null}
import { readFileSync } from 'node:fs';

const document = await client.documents.upload({
  submission_id: submission.id,
  file: readFileSync('./chase-jan-2026.pdf'),
  filename: 'chase-jan-2026.pdf',
});
```

```python Python icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/python.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=a9a026d5d8b16735c0cea1b7dd0ac6e5" theme={null}
document = client.documents.upload(
    submission.id,
    file="./chase-jan-2026.pdf",
)
```

```go Go icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/go.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=338b141516fd81c7c6c2302fdf1e318b" theme={null}
f, err := os.Open("./chase-jan-2026.pdf")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

document, err := client.Documents.Upload(ctx, submission.Id, "chase-jan-2026.pdf", f)
```

> [!TIP]
>
> Pass `document_class` if you already know the type and want to skip classification.

**3. Wait for processing**

Parsing and enrichment are asynchronous. Poll the submission until it leaves the processing states — the TypeScript and Python SDKs ship a helper that does exactly this.

```bash cURL icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/curl.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=317cbd8cd7548ad8579adf23d3bd0ec9" theme={null}
curl http://localhost:3000/v1/submissions/$SUBMISSION_ID/status \
  -H "Authorization: Bearer $MONEYLINE_API_KEY"
```

```ts TypeScript icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/typescript.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=cba1e12257cdbf42b6c7a23031def04f" theme={null}
// Polls until status is processed / reviewed / failed (default timeout 5 min).
const processed = await client.submissions.waitForProcessing(submission.id, {
  timeout: 300_000,
  pollInterval: 5_000,
});
```

```python Python icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/python.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=a9a026d5d8b16735c0cea1b7dd0ac6e5" theme={null}
processed = client.submissions.wait_for_processing(submission.id, timeout=300)
```

```go Go icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/go.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=338b141516fd81c7c6c2302fdf1e318b" theme={null}
// Go has no polling helper — check the status yourself.
status, err := client.Submissions.GetProcessingStatus(ctx, submission.Id)
```

> [!NOTE]
>
> In production, prefer [webhooks](https://docs.moneyline.co/guides/webhooks.md) over polling: subscribe to
> `submission.processed` and react to the event.

**4. List the extracted transactions**

Transactions come back enriched — categorized, merchant-matched, and deduplicated.

```bash cURL icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/curl.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=317cbd8cd7548ad8579adf23d3bd0ec9" theme={null}
curl "http://localhost:3000/v1/transactions?submission_id=$SUBMISSION_ID&limit=25" \
  -H "Authorization: Bearer $MONEYLINE_API_KEY"
```

```ts TypeScript icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/typescript.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=cba1e12257cdbf42b6c7a23031def04f" theme={null}
// `list` returns an async iterator that pages transparently.
for await (const txn of client.transactions.list({ submission_id: submission.id })) {
  console.log(txn.postedAt, txn.amount, txn.category);
}
```

```python Python icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/python.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=a9a026d5d8b16735c0cea1b7dd0ac6e5" theme={null}
for txn in client.transactions.list(submission_id=submission.id):
    print(txn.posted_at, txn.amount, txn.category)
```

```go Go icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/go.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=338b141516fd81c7c6c2302fdf1e318b" theme={null}
page, err := client.Transactions.List(ctx, &moneyline.ListTransactionsParams{
	SubmissionID: submission.Id,
	Limit:        25,
})
```

**5. Read the analytics**

Every calculation lives on the `analytics` resource — not on `submissions`.

```bash cURL icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/curl.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=317cbd8cd7548ad8579adf23d3bd0ec9" theme={null}
curl http://localhost:3000/v1/submissions/$SUBMISSION_ID/scorecard \
  -H "Authorization: Bearer $MONEYLINE_API_KEY"
```

```ts TypeScript icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/typescript.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=cba1e12257cdbf42b6c7a23031def04f" theme={null}
const scorecard = await client.analytics.getScorecard(submission.id);
const cashflow = await client.analytics.getCashflow(submission.id);
const risk = await client.analytics.getRiskScore(submission.id);
```

```python Python icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/python.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=a9a026d5d8b16735c0cea1b7dd0ac6e5" theme={null}
scorecard = client.analytics.scorecard(submission.id)
cashflow = client.analytics.cashflow(submission.id)
risk = client.analytics.risk_score(submission.id)
```

```go Go icon="https://mintcdn.com/paragon-f28ba471/UuDHN4B1J-v_DThS/images/lang/go.svg?fit=max&auto=format&n=UuDHN4B1J-v_DThS&q=85&s=338b141516fd81c7c6c2302fdf1e318b" theme={null}
scorecard, err := client.Analytics.GetScorecard(ctx, submission.Id)
cashflow, err := client.Analytics.GetCashflow(ctx, submission.Id)
risk, err := client.Analytics.GetRiskScore(ctx, submission.Id)
```

There are fifteen analytics methods in every SDK — balances, anomalies, forecasts, recurring payments, merchant summaries, categories, and more. See the [SDK reference](https://docs.moneyline.co/sdks/overview.md) for the full list.

## Next steps

> **[Concepts](https://docs.moneyline.co/get-started/concepts.md)**
>
> The data model behind submissions, documents, and transactions.

> **[Webhooks](https://docs.moneyline.co/guides/webhooks.md)**
>
> React to processing events instead of polling.

> **[Pagination](https://docs.moneyline.co/guides/pagination.md)**
>
> Cursor pagination, and the auto-paging helpers in each SDK.

> **[Errors](https://docs.moneyline.co/get-started/errors.md)**
>
> The error envelope, and the typed errors each SDK raises.

NextShip itYou have a submission, a parsed document, and analytics. Next: react to events instead of polling, and give every write an idempotency key.

[Set up webhooks](https://docs.moneyline.co/guides/webhooks.md)
[Browse the SDKs](https://docs.moneyline.co/sdks/overview.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.