---
url: https://flat.io/developers/docs/api/omr.md
description: >-
  Turn PDFs and photos of sheet music into editable Flat scores through the API.
  Overview of the two OMR import flows, scopes, credits, capabilities, and
  errors.
---

# Optical Music Recognition (OMR)

Flat's **Optical Music Recognition** turns a PDF or photo of sheet music into music you can use: a
fully editable score in the Flat Library, or a MusicXML or MIDI file for your own tools. You send the
file, Flat recognizes the staves, notes, and symbols, and you get back the result to play, edit, and
export.

> Looking for the end-user OMR feature instead? See the
> [OMR help center article](https://help.flat.io/en/music-notation-software/omr/) and its
> [changelog](https://help.flat.io/en/music-notation-software/omr/changelog/). If you or your users
> just want to turn files into scores without writing code, and without a Flat account, try
> [Opuscan](https://www.opuscan.com/omr/), our dedicated scan-to-score product.

![Optical Music Recognition converts a PDF or photo of sheet music into an editable Flat score, or a downloadable MusicXML or MIDI file.](/img/omr/hero.png)

## Powered by Tutteo's own AI model

Every PDF and photo is processed by **[Tutteo](https://tutteo.com)'s own in-house deep-learning
model**, the Optical Music Recognition engine built by our company, [Tutteo](https://tutteo.com),
behind [Flat](https://flat.io) and [Opuscan](https://www.opuscan.com/omr/), not a third-party engine. It does not just spot symbols, it reads them in musical context, the way a trained
musician would, so the score it rebuilds actually makes sense.

* **Reads in context.** Rhythm, pitch, and layout are read together, not symbol by symbol.
* **Understands structure.** Separates instruments and voices, and attaches lyrics, chords, and text
  to the right notes.
* **Improves with every release.** Built end to end in-house, so recognition gets measurably better
  over time.

## Two ways to import

There are two ways to run OMR through the API:

* The **[Interactive Jobs API](/api/omr/jobs)** gives the **best results**. You can set the locales,
  review and correct the detected instruments and title, follow live progress, and export MusicXML
  without adding it to your Flat Library. It also supports adding pages one by one (ideal for mobile
  capture). This
  is the recommended path for a polished integration.
* The **[Auto simple import](/api/omr/import)** is the **fewest calls** and shares one code path with
  your MusicXML and MIDI imports: send a file to `POST /scores`, poll the task, get a score. Reach for
  it when you just want a Library score and do not need the review step or progress.

| | Interactive Jobs API | Auto simple import |
|:--|:--|:--|
| **Endpoint** | [`/omr/jobs/*`](https://flat.io/developers/docs/api/reference#tag/OMR) | [`POST /scores`](https://flat.io/developers/docs/api/reference#tag/Score/operation/createScore) (+ [tasks](https://flat.io/developers/docs/api/reference#tag/Task/operation/getTask)) |
| **Best for** | Controlling instruments and locales, a progress UI, multi-image or mobile capture | A single PDF, or unifying MusicXML / MIDI / PDF import behind one call |
| **Result** | A Library score, or a MusicXML file you download directly (without importing it into the Library) | A score in the Flat Library |
| **Review step** | Optional `details` step (correct title, language, instruments) | No |
| **Live progress** | Long-polling with a localized progress key | Task `percent` |
| **Calls to ship** | 3 or more | 2 |

## The developer dashboard

The [developer dashboard](https://flat.io/developers/omr) shows the OMR activity of your Flat
account: the same jobs, credits, and results the API returns, whichever token or app created them.

| View | What it shows |
|:--|:--|
| [Get started](https://flat.io/developers/omr) | Your balance, a link to create a token with the `omr` scope, and your most recent jobs. |
| [Playground](https://flat.io/developers/omr/playground) | Runs a job on one of your files with `output: musicxml`, so nothing is added to your library. The charge is confirmed before the job starts. |
| [Jobs](https://flat.io/developers/omr/jobs) | Every job on the account, filterable by `status` and retention state, with the same fields as [`GET /omr/jobs`](https://flat.io/developers/docs/api/reference#tag/OMR/operation/listOmrJobs). |
| Job page (`/developers/omr/jobs/{job}`) | One job: live progress, the `details` review step when it pauses, the downloads, the retention deadline, and a button to erase its files now. |
| [Credits](https://flat.io/developers/billing/credits) | The balance per pool and the credit ledger, the same data as [`GET /billing/credits/history`](https://flat.io/developers/docs/api/reference#tag/OMR/operation/listBillingCreditsHistory). |

Jobs and credits are **account-wide**: the Playground, your scripts, and every app on the account
share one list and one balance.

## Authentication and scopes

Every OMR request is authenticated like the rest of the API (see [Authentication](/api/authentication)).
A [Personal Access Token](/api/authentication#personal-access-tokens) is the quickest way to start.

For OAuth2 apps, request these scopes:

| Scope | When you need it |
|:--|:--|
| `omr` | Every OMR request (both flows). |
| `scores` | Additionally, whenever OMR **creates a score** in the Library: the Auto simple import, and the Interactive Jobs API with `output: library` (the default). Not needed for `output: musicxml`. |

In the Interactive Jobs API, a request that creates a Library score without the `scores` scope is
rejected with `403` (`OMR_SCORES_SCOPE_REQUIRED`). The Auto simple import enforces the `scores` scope
through the standard endpoint scope check, and separately returns `403` (`OMR_SCOPE_REQUIRED`) when the
`omr` scope is missing. Personal access tokens and web sessions carry the account's own permissions and
are not subject to these OAuth scope checks.

## Capabilities and credits

OMR runs on **credits** tied to a Flat account, charged **per page** at job start. Call
[`GET /omr/capabilities`](https://flat.io/developers/docs/api/reference#tag/OMR/operation/getOmrCapabilities)
to feature-detect at runtime instead of hardcoding limits: it returns the supported steps, export
formats and outputs, the file, page, and parallel-job limits, `costPerPage`, and the account's
`remainingCredits`. See the
[`getOmrCapabilities`](https://flat.io/developers/docs/api/reference#tag/OMR/operation/getOmrCapabilities)
reference for the full response.

The response also carries `retentionDays` (30 by default), how long a job's files and results are
kept, and `localesDetails`, the recognition languages with their English names, ready for a language
picker. See [Retention and deletion](/api/omr/jobs#retention-and-deletion).

No authentication is needed to call it, so you can feature-detect before a user connects their
account. Called without one, the limits returned are those of the free plan and `remainingCredits`
is omitted, since there is no account to report a balance for.

**1 credit is 1 page** (`costPerPage` is `1`), drawn from the **same pool as the Flat web,
desktop, and mobile apps**. There is no separate API meter.

Read `remainingCredits` before you start a job so a user never discovers the problem as a failure:

::: code-group

```bash [curl]
curl -H "Authorization: Bearer $TOKEN" "https://api.flat.io/v2/omr/capabilities"
```

```js [JavaScript]
const caps = await fetch('https://api.flat.io/v2/omr/capabilities', { headers: auth }).then((r) => r.json());

if (pageCount * caps.costPerPage > caps.remainingCredits) {
  // Send the user to https://flat.io/settings/ai-credits before starting the job.
}
```

```python [Python]
caps = requests.get("https://api.flat.io/v2/omr/capabilities", headers=auth).json()

if page_count * caps["costPerPage"] > caps["remainingCredits"]:
    # Send the user to https://flat.io/settings/ai-credits before starting the job.
    ...
```

:::

### Current limits

These are today's values, given so you can size an integration before writing code. They are not
contractual, and an unauthenticated call reports the free plan's limits, so read them from
`GET /omr/capabilities` with your own token rather than hardcoding them.

| Limit | Current value | Capabilities field |
|:--|:--|:--|
| Pages per job | 50 | `maxPages` |
| Files per job | 100 | `maxFiles` |
| Size per file | 25 MiB | `maxFileSize` |
| Jobs processing in parallel | 10 per account | `maxParallelJobs` |
| Accepted input types | PDF, JPEG, PNG, WebP, TIFF, GIF, AVIF, HEIC, HEIF | `acceptedMimeTypes` |

These limits are adjustable: [contact us](mailto:developers@flat.io) if your workload needs more.
They are separate from the API [rate limits](/api/rate-limits), which cap requests per hour.

### Processing time

A single-page document typically takes **around 30 seconds**, and occasionally up to about a minute
per page. Multi-page documents are processed partly in parallel depending on the pages, parts, and
instruments involved, so total time does not grow linearly with page count.

The [Interactive Jobs API](/api/omr/jobs#step-4-follow-progress) reports live `progress` and supports
long-polling, so you can show real progress instead of guessing.

### Whose credits are spent

Credits belong to the **Flat account that owns the token** you authenticate with:

* With a [Personal Access Token](/api/authentication#personal-access-tokens), that is your own account.
* With OAuth2, that is the account of the user who authorized your app.

For each job, credits are drawn in this order:

1. The page allowance included in the account's **Flat or Flat for Education subscription**.
2. **Credit packs** bought on the account. Packs do not expire while the account is active.

A single account can process files **on behalf of any number of end users**, who do not need Flat
accounts of their own. That is the usual shape for a commercial integration: your backend holds one
token, your users never see Flat. Use OAuth2 instead when each conversion should be billed to your
user's own Flat account.

::: warning Opuscan credits are separate
[Opuscan](https://www.opuscan.com/omr/) is a separate consumer product sold through the app stores.
Credits bought inside Opuscan are tied to that store account and **cannot be used with this API**,
and credits on your Flat account do not appear in Opuscan. See the
[FAQ](/api/omr/faq/credits#do-credits-bought-in-the-opuscan-apps-work-with-the-api).
:::

### Buying credits

Credit packs are purchased from
[your account's AI credits page](https://flat.io/settings/ai-credits?ref=dev-docs-omr). Packs run up
to 3,000 credits, and the price per page improves at every size, with the best rates on the largest
packs. Usage-based (pay as you
go) billing is planned for a future release.

Packs are **one-off purchases**: not a subscription, no auto-renewal, and no expiry while the account
is active. The 1,000 and 3,000 packs sit behind the **"Need 1000+ credits?"** link on that page
rather than in the default grid.

Credits are **only ultimately consumed by successful conversions**. They are charged when a job
starts, then reverted if the job ends in `error` or is
[canceled](/api/omr/jobs#cancel-a-job) before the worker finishes.

When the account is out of credits, over quota, or the plan does not include OMR, requests that
consume credits return **`402`**. Show `remainingCredits` and `costPerPage` to warn users before you
start a job, and point them to
[flat.io/settings/ai-credits](https://flat.io/settings/ai-credits?ref=dev-docs-omr) to top up.

Need more than the largest pack? [Contact us](mailto:developers@flat.io) to discuss custom pricing
and a contract for larger volumes.

## What OMR can read

OMR works best on clean, printed sheet music: engraved scores, good scans, and sharp photos, in
standard notation (single instruments, grand-staff, and multi-instrument scores). Handwritten music
and tablature are not supported. As a rule of thumb, if a page is hard for a person to read, it is
hard for Flat to read.

For the full, up-to-date details, see the help center:

* [Which notations are supported](https://help.flat.io/en/music-notation-software/omr/) (the complete recognition matrix).
* [Getting the best results](https://help.flat.io/en/music-notation-software/omr/) (capture and file-preparation tips).
* [OMR changelog](https://help.flat.io/en/music-notation-software/omr/changelog/) (recognition improvements over time).

For lyric language support, what to do about an inaccurate conversion, and how to tell which model
version produced a result, see the
[recognition quality FAQ](/api/omr/faq/quality).

## Commercial use, privacy, and terms

You can use OMR to process sheet music uploaded by customers who hold the necessary rights, and
deliver the resulting MusicXML and MIDI to them outside of Flat. No attribution is required, and
there is no requirement to keep the result in a Flat library. You and your users remain responsible
for having the appropriate rights to the source material.

**Files you submit, and the outputs generated from them, are not used to train or improve our
models.** Our recognition models are trained on synthetic data we generate ourselves and on
public-domain sheet music we source independently.

The API is covered by Flat's
[Terms of Service and Privacy Policy](https://help.flat.io/en/policies/). You can rely on our
published [Data Processing Addendum](https://help.flat.io/en/education/policies/data-processing-addendum/),
and our infrastructure providers, subprocessors, and hosting regions are documented in the
[data and infrastructure article](https://help.flat.io/en/general/data-infrastructure/#infrastructure-providers).

See the [commercial use, privacy, and data FAQ](/api/omr/faq/legal) for the detail, including exactly
what remains after a job is deleted.

## Errors

A failed **job** reports a stable `errorCode` plus a localized `errorMessage`. The Auto simple import
surfaces the same failures through the task's error message. `errorCode` is an open string: new codes
may be added, so branch on the ones you handle and keep a generic fallback.

| `errorCode` | Meaning |
|:--|:--|
| `NO_MUSIC_DETECTED` | No musical content found (poor scan, rotated page, or tablature). |
| `CORRUPTED_FILE` | The input file is corrupted and could not be read. |
| `UNSUPPORTED_FORMAT` | The file format or notation is not supported yet. |
| `UNSUPPORTED_TABLATURE` | The file is guitar tablature, not supported yet. |
| `ENCRYPTED_PDF` | The PDF is password-protected. |
| `TOO_LARGE` | The document is too large or has an unusual shape to process. |
| `ENGINE_TIMEOUT` | Recognition took longer than expected and was stopped. |
| `GENERIC` | Unspecified failure. |

HTTP statuses you should handle:

| Status | When it happens |
|:--|:--|
| `400` | Invalid request, for example adding a file to a job that is no longer a draft (`OMR_JOB_NOT_DRAFT`), or a file whose type cannot be determined (`OMR_MIME_REQUIRED`). |
| `402` | Out of credits, over quota, or OMR not included in the plan. See [Buying credits](#buying-credits) and [Why did I get a 402?](/api/omr/faq/credits#why-did-i-get-a-402). |
| `403` | Missing a required scope: `OMR_SCOPE_REQUIRED` (the `omr` scope), or `OMR_SCORES_SCOPE_REQUIRED` (the `scores` scope for Library output in the Jobs API). Also returned when acting on a job the account does not own. |
| `404` | Job, task, or export not found (or the requested export format is not available). |
| `409` | State conflict, for example submitting a step the job is not awaiting, or canceling a job the worker is actively processing. Also `OMR_JOB_EXPIRED` when the job's data has been erased, `OMR_JOB_IN_PROGRESS` when deleting a job that has not finished, and `OMR_JOB_NOT_EXPIRABLE` when deleting a job whose result went to the Library. |

See the [Errors](/api/errors) page for the general error response format.

## Next steps

* [Auto simple import](/api/omr/import) - the quickest path to a score.
* [Interactive Jobs API](/api/omr/jobs) - full control, progress, and the review step.
* [FAQ](/api/omr/faq/) - credits and billing, limits, recognition quality, and commercial use.
* [Instrument IDs](/api/instruments) - the catalog used to correct detected parts.
* [Developer dashboard](https://flat.io/developers/omr) - your jobs, credits, and a playground, without code.
* [API Reference: OMR](https://flat.io/developers/docs/api/reference#tag/OMR).
