> For the complete documentation index, see [llms.txt](https://knowledgebase.fabricdata.com/xytech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://knowledgebase.fabricdata.com/xytech/rest-api-v3/migrating-from-api-v2-to-api-v3.md).

# Migrating from API v2 to API v3

v3 runs **side by side** with v2 - nothing you have today stops working. You migrate by pointing calls at the `v3` path and adjusting for the changes below. You can migrate one endpoint at a time.

Each section states the change, shows a **v2 ? v3** before/after, and flags anything that could break a naive port.

### 1. Change the base path and drop the database

```diff
- GET https://<your-server>/api/v2/database/MyDatabase/JmJob/...
+ GET https://<your-server>/api/v3/JmJob/...
```

v3 **no longer takes a database in the URL** - the server uses its configured database automatically, so drop the `/database/{name}/` segment entirely.

> **Watch out:** the only exception is a server that hosts more than one database. There, add `?database=Name` to target one; otherwise the server falls back to its default. See [Base URL and databases](/xytech/rest-api-v3/api-v3-user-guide/base-url-and-databases.md).

### 2. Address records with path segments, not `key=value`

```diff
- GET https://<your-server>/api/v2/database/MyDatabase/JmJob/job_no=123
+ GET https://<your-server>/api/v3/JmJob/job_no/123
```

Because the value is now a path segment, `=` no longer appears in your URLs.

### 3. Retrieve records whose code contains `/`

A `/where/` route captures the rest of the path, slashes included:

```diff
- (not possible in v2)
+ GET https://<your-server>/api/v3/SchResource/where/resource_code=AVL/007
```

### 4. `fields` is now REQUIRED on every GET

This is the change most likely to break an existing integration. **Every v3 GET must include a `fields` parameter**, and it must be **JSON** (a comma-separated list is rejected):

```diff
- GET .../api/v2/.../JmJob/job_no=123
+ GET .../api/v3/JmJob/job_no/123?fields={"jm_job":["job_no","customer_name"]}
```

Omit it and you get `400 XY_MISSING_FIELD`; send a comma list and you get `400 XY_BAD_REQUEST`. The shape is `{"table": ["field", {"dropdown": ["key1","key2"]}]}`. Applies to single-record, setup, and list GETs. See [Querying list documents](/xytech/rest-api-v3/api-v3-user-guide/querying-list-documents-get.md).

### 5. A default page size is always applied

v3 always applies the system default page size (**200** unless your administrator changed `MAX_LIST_ROWS_REST_API`); larger requests are clamped.

> **Watch out:** if your v2 code assumed one response held *all* rows, it must now **page**. Read the total from the `Pagination-Count` response header and loop with `?page=`. See [Paging and sorting](/xytech/rest-api-v3/api-v3-user-guide/paging-and-sorting.md).

### 6. Send complex queries with POST

```diff
- GET .../api/v2/.../JmJoblist?query=<long, heavily-encoded filter>
+ POST .../api/v3/JmJoblist/query
+ { "filtering": { ... }, "paging": { ... }, "resultColumns": [ ... ] }
```

GET with `query` still works for simple cases. See [Querying with POST](/xytech/rest-api-v3/api-v3-user-guide/querying-with-post.md).

### 7. Filter setup documents

Setup documents (e.g. `TcActivity`, `JmPhase`, `MoTask`) can now be filtered with the same `query` and `fields` parameters as list documents, instead of returning every record. See [Querying setup documents](/xytech/rest-api-v3/api-v3-user-guide/querying-setup-documents.md).

### 8. PATCH content-type mapping is reversed from v2

v3 standardises PATCH bodies on the conventional mapping, which is the **opposite** of v2:

| Body                             | v2 `Content-Type`             | v3 `Content-Type`             |
| -------------------------------- | ----------------------------- | ----------------------------- |
| `[{op, path, value}]` operations | `application/json`            | `application/json-patch+json` |
| Document payload                 | `application/json-patch+json` | `application/json`            |

```diff
  PATCH https://<your-server>/api/v3/JmJob/job_no/123
- Content-Type: application/json                 # v2 op array
+ Content-Type: application/json-patch+json       # v3 op array
  [ { "op": "replace", "path": "job_desc", "value": "Barry" } ]
```

> **Watch out:** swap your PATCH `Content-Type` headers. See [Creating and updating documents](/xytech/rest-api-v3/api-v3-user-guide/creating-and-updating-documents.md).

### 9. Handle real HTTP status codes

v3 returns the **correct status** and a JSON body `{ status, code, error }`:

```diff
- HTTP/1.1 400 Bad Request
+ HTTP/1.1 404 Not Found
+ { "status": 404, "code": "XY_NOT_FOUND", "error": "..." }
```

| You'll now see                 | When                                          |
| ------------------------------ | --------------------------------------------- |
| `400` (with a specific `code`) | Validation / business-logic / bad-JSON errors |
| `401`                          | Missing or invalid credentials                |
| `403`                          | Authenticated but not permitted               |
| `404`                          | Document or record does not exist             |
| `500`                          | Unexpected server error                       |

> **Watch out:** branch on the HTTP status and the body `code` (not the free-text `error`, and not a blanket `400`). See [Error responses](/xytech/rest-api-v3/api-v3-user-guide/error-responses.md).

### Migration checklist

* [ ] Point calls at `/api/v3/...` and drop the `/database/{name}/` segment (add `?database=` only on multi-database servers).
* [ ] Convert `keyName=keyValue` addressing to `/keyName/keyValue`.
* [ ] Use `/where/{key}` for codes that can contain `/`.
* [ ] **Add a JSON `fields` parameter to every GET** (now mandatory).
* [ ] Add paging: read `Pagination-Count`, loop with `?page=`.
* [ ] Move heavy filters into a POST `/query` body where it helps.
* [ ] **Swap PATCH `Content-Type` headers** (mapping is reversed from v2).
* [ ] Rework error handling to branch on HTTP status + body `code`.
