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

# 契約フォルダを組み立て

> 複数ファイルの契約 JSON を 1 つの完全検証済みマニフェストへマージ。匿名可。

**`POST`** `https://api-datahub.octoparse.com/v1/data-apps/contract/assemble`

Authentication: none. Anonymous access allowed.

Merge a contract folder (a file map keyed by relative path, order preserved) into one self-contained manifest. This endpoint is the single source of truth for assembly rules. The portal import wizard and the contract skill self-check both use it.

Slot files: `dataapp.json` / `input_schema.json` / `output_schema.json` / `runtime.json` / `pricing.json` / `examples.json` / `README.md` (filenames are case-insensitive; dotted forms such as `input.schema.json` are accepted and normalized in `picked`). Pricing and examples may also be inlined in `dataapp.json`. The merged manifest goes through full author-side validation (same rules as Validate a manifest). Deliverable only when `issues` is empty. Recoverable anomalies (missing files, cross-layer name collisions, ignored non-contract files, folder name mismatch, and so on) return as structured `warnings` (`code` + `params`, localized by the presentation layer) and are not errors.

Hard failures (`400`): a slot file is not valid JSON, has the wrong shape (`examples.json` must be an array; other slots are objects), or exceeds 1MB; no contract file at all; total size over 12MB. The contract path covers api-kind only; `runtime.kind=code` produces an issue.

Optional 8th file `i18n.json` (`{source, locales}`, up to 4MB) is **not** merged into the manifest. It is parsed and returned as `translations` for the caller to save via the translation endpoints. `source` is required; illegal locales yield `400`; a locale equal to `source` is skipped with `i18n-locale-is-source`; path-level problems return as `i18n-*` warnings.

Anonymous access is allowed: assembly is a pure function of the request body, it neither reads nor writes platform data, and file/total size limits are the only gate.

## Request

### Request body

<ParamField body="files" type="object" required>
  File map. Keys are relative paths; values are file text.
</ParamField>

### Example request

```bash theme={null}
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"files": {"dataapp.json": "{\"spec_version\": \"0.2\", \"identity\": {…}}", "input_schema.json": "{\"type\": \"object\", …}", "output_schema.json": "{\"id_field\": \"review_id\", …}", "runtime.json": "{\"kind\": \"api\", …}", "pricing.json": "{\"events\": [...]}", "examples.json": "[...]", "README.md": "# Product review lookup"}}' \
  "https://api-datahub.octoparse.com/v1/data-apps/contract/assemble"
```

## Response

### 200 success

```json theme={null}
{
  "data": {
    "manifest": {
      "spec_version": "0.2",
      "identity": {
        "app_name": "reviews-query",
        "name": "Product review lookup"
      },
      "…": "…"
    },
    "picked": {
      "dataapp.json": "dataapp.json",
      "input_schema.json": "input_schema.json"
    },
    "issues": [],
    "warnings": [
      {
        "code": "contract-folder-name-mismatch",
        "params": {
          "expected": "reviews-query",
          "actual": "reviews"
        }
      }
    ],
    "card": {
      "app_name": "reviews-query",
      "name": "Product review lookup"
    },
    "translations": null
  }
}
```

The payload is wrapped in `data`. Fields:

<ResponseField name="manifest" type="object" required>
  Merged manifest object.
</ResponseField>

<ResponseField name="picked" type="string[]">
  Map of slot files that were actually recognized.
</ResponseField>

<ResponseField name="folder_name" type="string">
  —
</ResponseField>

<ResponseField name="issues" type="object[]">
  Validation issues. Empty means deliverable.

  <Expandable title="fields">
    <ResponseField name="path" type="string" required>
      —
    </ResponseField>

    <ResponseField name="message" type="string" required>
      —
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="warnings" type="object[]">
  Structured warnings.

  <Expandable title="fields">
    <ResponseField name="code" type="string" required>
      —
    </ResponseField>

    <ResponseField name="params" type="object">
      —
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="translations" type="object">
  Parsed `i18n.json` content, or `null` when absent.

  <Expandable title="fields">
    <ResponseField name="source" type="string" required>
      —
    </ResponseField>

    <ResponseField name="locales" type="object">
      —
    </ResponseField>
  </Expandable>
</ResponseField>

### Errors

| HTTP | `code`                  | `category`      | Description                                                                                                 |
| ---- | ----------------------- | --------------- | ----------------------------------------------------------------------------------------------------------- |
| 400  | `contract-file-invalid` | `invalid_input` | A contract file is not valid JSON, has the wrong shape, or exceeds 1MB; or `i18n.json` is missing `source`. |
| 400  | `contract-empty`        | `invalid_input` | The file set contains no contract slot files.                                                               |
| 400  | `locale-invalid`        | `invalid_input` | Locale code is invalid.                                                                                     |
| 413  | `payload-too-large`     | `invalid_input` | Request body exceeds the size limit.                                                                        |

Error responses use `{"error": {code, category, message, retryable}}`. See <a href="/docs/jp/datahub/api/reference/introduction#errors">Errors</a>.

## Client libraries

The Python and JavaScript SDKs do not wrap this endpoint yet. Call REST directly.
