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

# Analyze word counts and match statistics

> Create and read Phrase TMS analyses over the API. Covers word and character counts, match statistics, net rate discounts, and the CSV, CSV_EXTENDED, LOG, and JSON export formats.

Analysis calculates word and character counts and match statistics for a translation job, so you can quote work, plan workload, and measure post-editing effort over the API. This guide covers creating an analysis, reading its results, and the four downloadable export formats.

Analysis is a feature of Phrase TMS (Translation Management System). For a walkthrough of the Analysis screen in the product, see the [Analysis (TMS)](https://support.phrase.com/hc/en-us/articles/5709712007708-Analysis-TMS) support article.

## Quickstart

The simplest call fetches one analysis you already have and confirms your token works. Replace the base URL, token, and analysis UID with your own.

```bash theme={null}
curl --request GET "${TMS_BASE_URL}/api2/v3/analyses/${ANALYSE_UID}" \
  --header "Authorization: Bearer ${ACCESS_TOKEN}"
```

A `200` response returns the analysis and its per language pair results. If you get a `401`, your access token is missing or expired; refresh it and try again. See [Get analysis](/en/api/tms/latest/analysis/get-analysis) for the full response shape.

## Prerequisites

| Prerequisite                  | Details                                                                                                                           |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Phrase TMS access             | An account with permission to view or run analyses.                                                                               |
| A job or an existing analysis | A job UID to analyze, or an analysis UID to read.                                                                                 |
| Authentication set up         | A valid access token, sent as `Authorization: Bearer <token>`. See the [Authentication](/en/api/tms/latest/authentication) guide. |

## How analysis works

Analysis splits a job's segments into bands, such as translation memory (TM) matches, machine translation (MT) matches, internal fuzzy matches, non-translatables, and repetitions. Each band carries its own counts. A *segment* is one translatable unit of text, usually a sentence.

Results are always per language pair, calculated against that pair's own TM, even when several target languages share one TM.

### Analysis types

The `type` you choose decides what gets measured.

| Type                                                 | Runs on                                  | Purpose                                                                           |
| ---------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------- |
| Default (`PreAnalyse`)                               | Source segments, before translation      | Baseline word and character counts for quotes and workload planning               |
| Target (`PreAnalyse` with `countSourceUnits: false`) | Target segments                          | The same breakdown, counted against target-language content instead of source     |
| Post-editing (`PostAnalyse`)                         | Target segments, after translation or MT | Editing effort: how much a linguist or reviewer had to change                     |
| Compare (`Compare`)                                  | Two workflow steps of one job            | Segment-level difference in word and character counts between two workflow levels |

A *linguist* is a translator or reviewer working on the job.

## Creating an analysis

[Create analysis](/en/api/tms/latest/analysis/create-analysis) takes a job selection and a `type`. The job selection is either `jobs` (job UIDs from the same project) or `jobFilter` (a project plus optional filename, status, target languages, workflow step, provider, or due-date filters). The `type` picks what gets measured.

| `type`        | Measures                                                                          | Type-specific options                                                                                                                         |
| ------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `PreAnalyse`  | Source segments, before translation, the baseline for quotes and workload         | `countSourceUnits` (source vs. target counts), `skipMtScoreThreshold`                                                                         |
| `PostAnalyse` | Post-editing effort on target segments, after translation or MT                   | `transMemoryPostEditing`, `machineTranslatePostEditing`, `nonTranslatablePostEditing`, each measuring edit distance against that match source |
| `Compare`     | Segment-level word and character difference between two workflow steps of one job | `compareWorkflowLevel` (required)                                                                                                             |

Options common to every type:

* `includeTransMemory`, `includeMachineTranslationMatches`, `includeNonTranslatables` decide which match sources count.
* `includeFuzzyRepetitions`, `separateFuzzyRepetitions` fold internal fuzzy matches into the regular bands or break them out.
* `includeNumbers`, `includeConfirmedSegments`, `includeLockedSegments`, `includeNotConfirmedSegments` decide which segments count at all.
* `name` supports macros such as `{projectName}`, `{sourceLang}`, and `{targetLang}`.
* `netRateScheme` applies a discount (see [Net rate schemes and discounts](#net-rate-schemes-and-discounts)).
* `useProjectAnalysisSettings` falls back to the project's [default analyse settings](/en/api/tms/latest/project/get-analyse-settings) instead of specifying everything inline.

To split the output instead of getting one combined analysis, either pass `analyzeByLanguage` or `analyzeByProvider` on the same request, or use the dedicated [Create analyses by languages](/en/api/tms/latest/analysis/create-analyses-by-languages) or [Create analyses by providers](/en/api/tms/latest/analysis/create-analyses-by-providers) endpoints for the same job selection. The by-providers endpoint also pre-applies a provider's net rate scheme, if one is assigned.

<Note>
  A source file update marks its analyses `outdated`. Recalculating re-applies the original settings. Vendors cannot recalculate analyses created by the buyer.
</Note>

### Working with analysis over the API

| Task                                                    | API operation                                                                                                                                      |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Create an analysis                                      | [Create analysis](/en/api/tms/latest/analysis/create-analysis)                                                                                     |
| Create one analysis per target language                 | [Create analyses by languages](/en/api/tms/latest/analysis/create-analyses-by-languages)                                                           |
| Create one analysis per provider                        | [Create analyses by providers](/en/api/tms/latest/analysis/create-analyses-by-providers)                                                           |
| Get an analysis's results                               | [Get analysis](/en/api/tms/latest/analysis/get-analysis)                                                                                           |
| Download an analysis (CSV, CSV\_EXTENDED, LOG, or JSON) | [Download analysis](/en/api/tms/latest/analysis/download-analysis)                                                                                 |
| Recalculate an outdated analysis                        | [Recalculate analysis](/en/api/tms/latest/analysis/recalculate-analysis)                                                                           |
| Delete an analysis                                      | [Delete analysis](/en/api/tms/latest/analysis/delete-analysis)                                                                                     |
| Get or edit a project's default analysis settings       | [Get analyse settings](/en/api/tms/latest/project/get-analyse-settings), [Edit analyse settings](/en/api/tms/latest/project/edit-analyse-settings) |

## Interpreting results

Each language pair's result (`analyseLanguageParts[].data`) breaks counts into buckets. Every bucket carries `segments`, `words`, `characters`, `normalizedPages`, `percent`, and `editingTime`.

| Bucket                      | Meaning                                                                                                                                                                                                                                |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `all`                       | Totals across every bucket below                                                                                                                                                                                                       |
| `repetitions`               | Duplicate segments. Only the *first* occurrence of a repeated segment is counted in its match or fuzzy bucket; every later occurrence is counted here instead.                                                                         |
| `transMemoryMatches`        | TM match bands: `match101` (in-context exact), `match100` (exact), `match95` (95 to 99 percent), `match85` (85 to 94 percent), `match75` (75 to 84 percent), `match50` (50 to 74 percent), `match0` (0 to 49 percent, no usable match) |
| `internalFuzzyMatches`      | The same match bands, but matched against other segments in the job instead of the TM (enabled with "include" or "separate" internal fuzzies)                                                                                          |
| `machineTranslationMatches` | The same match bands, for MT-suggested segments                                                                                                                                                                                        |
| `nonTranslatablesMatches`   | The same match bands, for segments Phrase determined do not need translation                                                                                                                                                           |

<Note>
  `match95` means the 95 to 99 percent band, `match85` means 85 to 94 percent, and so on. The label is the band's lower bound, not an exact score. `match101` exists only for TM matches, and marks in-context exact matches (the same source text *and* the same surrounding context, not just the same text).
</Note>

Each language part also has a `discountedData` object with the same shape as `data`, reflecting the [net rate scheme](#net-rate-schemes-and-discounts) applied to that analysis, if any.

### Net rate schemes and discounts

A net rate scheme applies a discount to words, characters, and pages in specific match buckets. For example, TM 100 percent matches can be billed at 20 percent of the normal rate. Applying one populates `discountedData` alongside the raw `data`. The product shows this as the analysis's **Net rate** row.

| Task                                  | API operation                                                                                                      |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Create a net rate scheme              | [Create net rate scheme](/en/api/tms/latest/net-rate-scheme/create-net-rate-scheme)                                |
| List net rate schemes                 | [List net rate schemes](/en/api/tms/latest/net-rate-scheme/list-net-rate-schemes)                                  |
| Get a net rate scheme                 | [Get net rate scheme](/en/api/tms/latest/net-rate-scheme/get-net-rate-scheme)                                      |
| Set or remove a scheme on an analysis | [Set or remove net rate scheme for analyse](/en/api/tms/latest/analysis/set-or-remove-net-rate-scheme-for-analyse) |

A scheme can also be applied automatically. Pass `netRateScheme` on [Create analysis](/en/api/tms/latest/analysis/create-analysis), or use `analyzeByProvider` or [Create analyses by providers](/en/api/tms/latest/analysis/create-analyses-by-providers) to inherit the provider's assigned scheme.

## Export formats

[Download analysis](/en/api/tms/latest/analysis/download-analysis) (`GET /api2/v1/analyses/{analyseUid}/download?format=...`) returns a file in one of four formats: `CSV`, `CSV_EXTENDED`, `LOG`, or `JSON`. These are the same formats offered by the **Download** button in the product. This section is the field-by-field reference for each.

<Note>
  All four formats download as `application/octet-stream`, including `JSON`. Expect an attachment, not an inline JSON response.
</Note>

### Shared concepts

Every format reports the same underlying counts, laid out differently.

**Match bands**, how closely a segment matched something else, from best to worst:

| Band          | Meaning                                                                                                                                                                                |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Context Match | 101 percent: exact text match *and* matching surrounding context. TM only; no equivalent band for MT, internal fuzzy, or non-translatable.                                             |
| Repetitions   | The segment duplicates another segment already counted elsewhere in the job. Only the *first* occurrence is counted in its match band; every later occurrence is counted here instead. |
| 100%          | Exact text match, context not considered                                                                                                                                               |
| 95%-99%       | High fuzzy match                                                                                                                                                                       |
| 85%-94%       | Fuzzy match                                                                                                                                                                            |
| 75%-84%       | Fuzzy match                                                                                                                                                                            |
| 50%-74%       | Low fuzzy match                                                                                                                                                                        |
| No Match (0%) | No usable match                                                                                                                                                                        |
| Total         | The sum of every band above                                                                                                                                                            |

**Source levels**, where a match came from: **TM** (translation memory), **IF** (internal fuzzy, matched against other segments in the same job rather than the TM), **MT** (machine translation), and **NT** (non-translatable). `CSV`, `CSV_EXTENDED`, and `LOG` sum all levels together per band. `JSON` breaks each band down by level (see below).

**Units per band**: Segments, Words, Characters, Normalized pages, Percent (share of the job or part total), and Editing time.

**Weighted counts**: if the analysis has a net rate scheme (a discount), every count in every format is the *discounted* value, that is, raw units multiplied by the discount percentage for that level, band, and workflow step. `Percent` for the Total band is always `100`; for other bands it is recomputed as band divided by total, times 100, when a discount scheme is present.

<Warning>
  A few columns are reserved but not yet computed, so they are always `0`: **Tagging Errors** and **Placeables** (CSV and CSV\_EXTENDED), and **Translated** and **Format Change** (LOG). Do not rely on them.
</Warning>

### CSV and CSV\_EXTENDED

The layout is the same for both. `CSV_EXTENDED` (labeled "CSV with chars" in the product) just adds a **Characters** column to every band. There are two header rows, then one data row per analyzed job. There is no per language pair or analysis-total row.

**Row 1**, band labels: three blank leading cells, then one label per band, in order: `Context Match`, `Repetitions`, `100%`, `95%-99%`, `85%-94%`, `75%-84%`, `50%-74%`, `No Match`, `Total`.

**Row 2**, column headers: `File`, `Tagging Errors`, `Chars/Word`, then for each band above: `Segments`, `Words`, `Characters` *(CSV\_EXTENDED only)*, `Placeables`, `Percent`. The **Total** band drops `Percent`.

**Data rows**, one per job:

| Column                                                               | Value                                                                             |
| -------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| File                                                                 | `"<job title> \| <sourceLocale>><targetLocale>"`                                  |
| Tagging Errors                                                       | `0` (placeholder)                                                                 |
| Chars/Word                                                           | Source characters-per-word ratio                                                  |
| *(per band)* Segments / Words / \[Characters] / Placeables / Percent | Discount-weighted counts for that band. `Placeables` is always `0` (placeholder). |
| *(Total)* Segments / Words / Characters / Placeables                 | The same, with no Percent column                                                  |

Numbers are formatted with the `en_US` locale, up to two decimal places.

### LOG

Plain fixed-width text, not delimited. It repeats the same block first **per job**, then once more **per language part** as an aggregate (`Total: N files`):

```
File:               <job title>              (job block only)
Date:               <analysis creation date, UTC>
Project:            <project name>
Language direction: <sourceLocale> > <targetLocale>

Match Types       Segments        Words      Percent
Translated               0            0            0   (placeholder, always 0)
Context Match       <seg>        <words>      <pct>
Repetitions          <seg>        <words>      <pct>
Format Change             0            0            0   (placeholder, always 0)
100%                 <seg>        <words>      <pct>
95% - 99%            <seg>        <words>      <pct>
85% - 94%            <seg>        <words>      <pct>
75% - 84%            <seg>        <words>      <pct>
50% - 74%            <seg>        <words>      <pct>
No Match             <seg>        <words>      <pct>
Total                <seg>        <words>          100
Chars/word           <ratio>
```

Numbers use the `en_US` locale, right-padded to 12 characters: two decimals for percent and pages, one decimal otherwise.

### JSON

Structured and nested, the only format with a per source level breakdown. Shape (`AnalyseExportDto`):

```jsonc theme={null}
{
  "projectName": "string",
  "dateCreated": "string",          // ISO-8601, UTC
  "analyseLanguageParts": [
    {
      "sourceLang": "string",
      "targetLang": "string",
      "data": { /* DataExportDto: language-pair aggregate */ },
      "jobs": [
        { "fileName": "string", "data": { /* DataExportDto: per job */ } }
      ]
    }
  ]
}
```

`DataExportDto`:

```jsonc theme={null}
{
  "contextMatch": { /* CountsExportDto */ },
  "repetitions":  { /* CountsExportDto */ },
  "match100": { /* CountsWithCategoriesExportDto */ },
  "match95":  { /* CountsWithCategoriesExportDto */ },
  "match85":  { /* CountsWithCategoriesExportDto */ },
  "match75":  { /* CountsWithCategoriesExportDto */ },
  "match50":  { /* CountsWithCategoriesExportDto */ },
  "match0":   { /* CountsWithCategoriesExportDto */ },
  "total":    { /* CountsExportDto */ },
  "charsPerWords": 0.0
}
```

`CountsExportDto`, flat counts for one band:

```jsonc theme={null}
{ "segments": 0, "words": 0, "characters": 0, "normalizedPages": 0.0, "percent": 0.0, "editingTime": 0 }
```

`CountsWithCategoriesExportDto`, the same six fields, but each value is broken down by source level instead of being a plain number:

```jsonc theme={null}
{ "segments": { "sum": 0, "tm": 0, "if": 0, "mt": 0, "nt": 0 }, "words": { ... }, ... }
```

`sum` is the total across levels. `tm`, `if`, `mt`, and `nt` are the TM, internal-fuzzy, MT, and non-translatable shares.

<Note>
  `contextMatch`, `repetitions`, and `total` are flat (`CountsExportDto`, no level breakdown). Only the match-percentage bands (`match100` through `match0`) carry the `tm`, `if`, `mt`, and `nt` split. This export has no `discounted` or `estimate` field; those are available only from [Get analysis](/en/api/tms/latest/analysis/get-analysis), which uses a different, richer JSON shape than this download.
</Note>

#### Mapping to the live API

The [Get analysis](/en/api/tms/latest/analysis/get-analysis) response uses different field names for the same bands. Its `match101` is this export's `contextMatch`, and its `match100`, `match95`, `match85`, `match75`, `match50`, and `match0` line up one-to-one with the same-named fields here. `repetitions` and `all` or `total` exist in both, named similarly.

## Troubleshooting

| Symptom                          | Fix                                                                                                                                                                            |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Analysis is marked `outdated`    | A source file changed after the analysis ran. Re-run it with [Recalculate analysis](/en/api/tms/latest/analysis/recalculate-analysis), which re-applies the original settings. |
| `403` when recalculating         | Vendors cannot recalculate analyses created by the buyer. Ask the buyer to recalculate, or create your own analysis.                                                           |
| Counts look wrong for a language | Results are per language pair, against that pair's own TM. Confirm you are reading the right `analyseLanguagePart`.                                                            |
| Empty `analyseLanguageParts`     | The analysis may still be running. Analyses are created asynchronously; poll [Get analysis](/en/api/tms/latest/analysis/get-analysis) until the counts are populated.          |

For product or account questions, contact [Phrase support](https://support.phrase.com/hc/en-us). For help writing integration code against these endpoints, use your own developer or AI coding tools.

## Next steps

<CardGroup cols={2}>
  <Card title="Create analysis" icon="calculator" href="/en/api/tms/latest/analysis/create-analysis">
    Run a new analysis over a job selection.
  </Card>

  <Card title="Get analysis" icon="chart-bar" href="/en/api/tms/latest/analysis/get-analysis">
    Read the full result shape for a language pair.
  </Card>

  <Card title="Download analysis" icon="download" href="/en/api/tms/latest/analysis/download-analysis">
    Export results as CSV, CSV\_EXTENDED, LOG, or JSON.
  </Card>

  <Card title="Net rate schemes" icon="percent" href="/en/api/tms/latest/net-rate-scheme/list-net-rate-schemes">
    Apply match-band discounts to an analysis.
  </Card>
</CardGroup>

*Last reviewed: September 7, 2026. API changes are recorded in the [changelog](/en/changelog).*
