From 628c177f0139655c267e43015bdf71198af94eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Ciesielski?= Date: Tue, 8 Sep 2026 13:00:39 +0000 Subject: [PATCH 1/2] docs(API): document upload file_format and async state contract (STRINGS-3096) Clarify the POST /projects/{project_id}/uploads behavior: - file_format is optional and auto-detected when omitted; recommend omitting it rather than guessing, and note a provided value must match the file's actual content (not just the project main format). - Document the async contract: 201 on enqueue, poll the upload state field, where state:error signals a processing/parse failure. - Describe the upload state values (initialized, processing, success, error) and point the show endpoint at the poll workflow. Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/compiled.json | 15 +++++++++------ paths/uploads/create.yaml | 9 ++++++--- paths/uploads/show.yaml | 3 ++- schemas/upload.yaml | 2 ++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index 35e382c6d..913329ec3 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -1,3 +1,5 @@ +(node:3238) [DEP0169] DeprecationWarning: `url.parse()` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities. +(Use `node --trace-deprecation ...` to show where the warning was created) { "openapi": "3.0.3", "info": { @@ -2099,7 +2101,8 @@ "type": "string" }, "state": { - "type": "string" + "type": "string", + "description": "Processing state of the upload: `initialized`, `processing`, `success`, or `error`. `error` means processing failed — for example the file could not be parsed, or a provided `file_format` didn't match the file's actual content. Poll this field until it leaves `initialized`/`processing` to get the final outcome.\n" }, "error_message": { "type": "string", @@ -16811,7 +16814,7 @@ "/projects/{project_id}/uploads": { "post": { "summary": "Upload a new file", - "description": "Upload a new language file. Creates necessary resources in your project.\n\nNote: be aware of [upload limits](https://support.phrase.com/hc/en-us/articles/8548271212188-Phrase-Strings-Limits#file-size-upload-limits-0-0).\n", + "description": "Upload a new language file. Creates necessary resources in your project.\n\nThe upload is processed asynchronously: this endpoint returns `201 Created` once the file has been accepted and enqueued, not once processing has finished. Poll `GET /projects/{project_id}/uploads/{id}` and check the `state` field — `error` means processing failed (for example, an unparseable file or a `file_format` that doesn't match the file's actual content).\n\nNote: be aware of [upload limits](https://support.phrase.com/hc/en-us/articles/8548271212188-Phrase-Strings-Limits#file-size-upload-limits-0-0).\n", "operationId": "upload/create", "tags": [ "Uploads" @@ -16869,11 +16872,11 @@ "x-code-samples": [ { "lang": "Curl", - "source": "curl \"https://api.phrase.com/v2/projects/:project_id/uploads\" \\\n -u USERNAME_OR_ACCESS_TOKEN \\\n -X POST \\\n -F branch=my-feature-branch \\\n -F file=@/path/to/my/file.json \\\n -F file_format=json \\\n -F locale_id=abcd1234cdef1234abcd1234cdef1234 \\\n -F tags=awesome-feature,needs-proofreading \\\n -F locale_mapping[en]=2 \\\n -F format_options[foo]=bar" + "source": "curl \"https://api.phrase.com/v2/projects/:project_id/uploads\" \\\n -u USERNAME_OR_ACCESS_TOKEN \\\n -X POST \\\n -F branch=my-feature-branch \\\n -F file=@/path/to/my/file.json \\\n -F locale_id=abcd1234cdef1234abcd1234cdef1234 \\\n -F tags=awesome-feature,needs-proofreading \\\n -F locale_mapping[en]=2 \\\n -F format_options[foo]=bar" }, { "lang": "CLI v2", - "source": "phrase uploads create \\\n--project_id \\\n--branch my-feature-branch \\\n--file /path/to/my/file.json \\\n--file_format json \\\n--locale_id abcd1234cdef1234abcd1234cdef1234 \\\n--tags awesome-feature,needs-proofreading \\\n--locale_mapping '{\"en\": \"2\"}' \\\n--format_options '{\"foo\": \"bar\"}' \\\n--access_token " + "source": "phrase uploads create \\\n--project_id \\\n--branch my-feature-branch \\\n--file /path/to/my/file.json \\\n--locale_id abcd1234cdef1234abcd1234cdef1234 \\\n--tags awesome-feature,needs-proofreading \\\n--locale_mapping '{\"en\": \"2\"}' \\\n--format_options '{\"foo\": \"bar\"}' \\\n--access_token " } ], "requestBody": { @@ -16901,7 +16904,7 @@ "example": "/path/to/my/file.json" }, "file_format": { - "description": "File format. Auto-detected when possible and not specified.", + "description": "File format of the uploaded file (e.g. `json`, `simple_json`, `yml`). Optional — when omitted, the format is auto-detected from the file's content. We recommend omitting this parameter and letting auto-detection handle it rather than guessing.\n\nIf provided, it must match the actual content of the file being uploaded, not just the project's main format — a mismatch causes the upload to fail (see `state: error`).\n", "type": "string", "example": "json" }, @@ -17115,7 +17118,7 @@ "/projects/{project_id}/uploads/{id}": { "get": { "summary": "Get a single upload", - "description": "View details and summary for a single upload.", + "description": "View details and summary for a single upload. Use this endpoint to poll for the outcome of an upload created via `POST /projects/{project_id}/uploads` — check the `state` field.\n", "operationId": "upload/show", "tags": [ "Uploads" diff --git a/paths/uploads/create.yaml b/paths/uploads/create.yaml index d1f4ca810..547a50f1c 100644 --- a/paths/uploads/create.yaml +++ b/paths/uploads/create.yaml @@ -2,6 +2,8 @@ summary: Upload a new file description: | Upload a new language file. Creates necessary resources in your project. + The upload is processed asynchronously: this endpoint returns `201 Created` once the file has been accepted and enqueued, not once processing has finished. Poll `GET /projects/{project_id}/uploads/{id}` and check the `state` field — `error` means processing failed (for example, an unparseable file or a `file_format` that doesn't match the file's actual content). + Note: be aware of [upload limits](https://support.phrase.com/hc/en-us/articles/8548271212188-Phrase-Strings-Limits#file-size-upload-limits-0-0). operationId: upload/create tags: @@ -44,7 +46,6 @@ x-code-samples: -X POST \ -F branch=my-feature-branch \ -F file=@/path/to/my/file.json \ - -F file_format=json \ -F locale_id=abcd1234cdef1234abcd1234cdef1234 \ -F tags=awesome-feature,needs-proofreading \ -F locale_mapping[en]=2 \ @@ -55,7 +56,6 @@ x-code-samples: --project_id \ --branch my-feature-branch \ --file /path/to/my/file.json \ - --file_format json \ --locale_id abcd1234cdef1234abcd1234cdef1234 \ --tags awesome-feature,needs-proofreading \ --locale_mapping '{"en": "2"}' \ @@ -83,7 +83,10 @@ requestBody: format: binary example: "/path/to/my/file.json" file_format: - description: File format. Auto-detected when possible and not specified. + description: | + File format of the uploaded file (e.g. `json`, `simple_json`, `yml`). Optional — when omitted, the format is auto-detected from the file's content. We recommend omitting this parameter and letting auto-detection handle it rather than guessing. + + If provided, it must match the actual content of the file being uploaded, not just the project's main format — a mismatch causes the upload to fail (see `state: error`). type: string example: json locale_id: diff --git a/paths/uploads/show.yaml b/paths/uploads/show.yaml index 61495e98d..3e9a4a759 100644 --- a/paths/uploads/show.yaml +++ b/paths/uploads/show.yaml @@ -1,6 +1,7 @@ --- summary: Get a single upload -description: View details and summary for a single upload. +description: | + View details and summary for a single upload. Use this endpoint to poll for the outcome of an upload created via `POST /projects/{project_id}/uploads` — check the `state` field. operationId: upload/show tags: - Uploads diff --git a/schemas/upload.yaml b/schemas/upload.yaml index 6bff13f46..4fca56474 100644 --- a/schemas/upload.yaml +++ b/schemas/upload.yaml @@ -11,6 +11,8 @@ upload: type: string state: type: string + description: | + Processing state of the upload: `initialized`, `processing`, `success`, or `error`. `error` means processing failed — for example the file could not be parsed, or a provided `file_format` didn't match the file's actual content. Poll this field until it leaves `initialized`/`processing` to get the final outcome. error_message: type: string nullable: true From 91ec7562a53788baf786033696b82cb8419dd554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Ciesielski?= Date: Fri, 11 Sep 2026 12:06:12 +0000 Subject: [PATCH 2/2] docs(API): revise file_format guidance per review feedback (STRINGS-3096) Address jablan's review comments: stop recommending that callers omit file_format, point to the Formats API endpoint for the identifier list instead of an external support article, and keep the JSON-ambiguity note tight rather than expanding auto-detection guidance further. Co-Authored-By: Claude Sonnet 5 --- doc/compiled.json | 4 +--- paths/uploads/create.yaml | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index 913329ec3..0fb70590f 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -1,5 +1,3 @@ -(node:3238) [DEP0169] DeprecationWarning: `url.parse()` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities. -(Use `node --trace-deprecation ...` to show where the warning was created) { "openapi": "3.0.3", "info": { @@ -16904,7 +16902,7 @@ "example": "/path/to/my/file.json" }, "file_format": { - "description": "File format of the uploaded file (e.g. `json`, `simple_json`, `yml`). Optional — when omitted, the format is auto-detected from the file's content. We recommend omitting this parameter and letting auto-detection handle it rather than guessing.\n\nIf provided, it must match the actual content of the file being uploaded, not just the project's main format — a mismatch causes the upload to fail (see `state: error`).\n", + "description": "File format of the uploaded file, given as a format's `api_name`. See our [Formats API Endpoint](/en/api/strings/formats/list-formats) for the full list of supported formats.\n\nOptional. When omitted, Phrase tries to auto-detect the format from the file's content. This is not always possible for JSON files, since several JSON-based formats (e.g. `json`, `simple_json`, `nested_json`) share the same structure.\n", "type": "string", "example": "json" }, diff --git a/paths/uploads/create.yaml b/paths/uploads/create.yaml index 547a50f1c..97aff21f2 100644 --- a/paths/uploads/create.yaml +++ b/paths/uploads/create.yaml @@ -84,9 +84,9 @@ requestBody: example: "/path/to/my/file.json" file_format: description: | - File format of the uploaded file (e.g. `json`, `simple_json`, `yml`). Optional — when omitted, the format is auto-detected from the file's content. We recommend omitting this parameter and letting auto-detection handle it rather than guessing. + File format of the uploaded file, given as a format's `api_name`. See our [Formats API Endpoint](/en/api/strings/formats/list-formats) for the full list of supported formats. - If provided, it must match the actual content of the file being uploaded, not just the project's main format — a mismatch causes the upload to fail (see `state: error`). + Optional. When omitted, Phrase tries to auto-detect the format from the file's content. This is not always possible for JSON files, since several JSON-based formats (e.g. `json`, `simple_json`, `nested_json`) share the same structure. type: string example: json locale_id: