# Saving data

**Endpoint:** `POST /api/tickets/multi`

Create, update, and delete records in a single batch request. The endpoint accepts an array of operations.

info

The API uses `transition` as the JSON field name for historical reasons. It refers to an **action** - the operation performed on a record (create, edit, delete, or a custom action like approve or close).

## Permissions[​](#permissions "Direct link to Permissions")

All write operations respect the authenticated user's permissions. The API returns an error if the user is not authorized to perform the requested action on the target record or app.

## Creating records[​](#creating-records "Direct link to Creating records")

Send an array with one or more record objects. Each object must include:

* `transition: "add"` - the action alias for creating a record
* `app_alias` - app type (e.g., `"TASK"`, `"TICKET"`)
* `workspace_alias` - target workspace (e.g., `"IT"`)
* Field values keyed by field name

```
curl --request POST \
  --url "https://acme.comind.work/api/tickets/multi" \
  --header "Authorization: CMW_AUTH_CODE YOUR-TOKEN" \
  --header "Content-Type: application/json" \
  --data '[{
    "transition": "add",
    "app_alias": "TASK",
    "workspace_alias": "HELPDESK",
    "title": "New task via API",
    "priority": "high",
    "description": "<!-- html --><p>Task description here</p>"
  }]'
```

### Response[​](#response "Direct link to Response")

```
[
  {
    "successful": true,
    "created": true,
    "data": {
      "id": "new-record-guid",
      "number": 456,
      "project_alias": "HELPDESK",
      "publishing_alias": "TASK"
    },
    "warnings": []
  }
]
```

### Rich text fields[​](#rich-text-fields "Direct link to Rich text fields")

Prefix HTML content with `<!-- html -->` to indicate it should be stored as rich text:

```
{
  "description": "<!-- html --><p>This is <strong>formatted</strong> text</p>"
}
```

Plain text and markdown are also accepted - the server converts them to HTML automatically. The `<!-- html -->` prefix tells the API the content is already HTML and should not be converted.

Markdown conversion supports `**bold**`, `*italic*`, `[link](url)`, and paragraph breaks (double newlines).

### Lookup values[​](#lookup-values "Direct link to Lookup values")

Lookup fields (state, priority, custom dropdowns) require internal db values, not display captions. Use `GET /api/schema/{WS}!{APP}` to discover lookup values:

```
{ "priority": "high" }
{ "state": "open" }
```

## Updating records[​](#updating-records "Direct link to Updating records")

Provide the record `id` and the action alias in the `transition` field:

```
curl --request POST \
  --url "https://acme.comind.work/api/tickets/multi" \
  --header "Authorization: CMW_AUTH_CODE YOUR-TOKEN" \
  --header "Content-Type: application/json" \
  --data '[{
    "id": "record-guid",
    "transition": "edit",
    "title": "Updated title",
    "priority": "high",
    "comment": "<!-- html --><p>Changed priority</p>"
  }]'
```

Only include fields you want to change. Omitted fields are not modified.

### Available actions[​](#available-actions "Direct link to Available actions")

Use the schema endpoint to discover which actions are available for an app:

```
GET /api/schema/{workspace}!{app}
```

The `transitions` array in the schema response lists available actions with their aliases:

| Common alias | Purpose                                                    |
| ------------ | ---------------------------------------------------------- |
| `edit`       | General edit (most apps)                                   |
| `add`        | Create a new record                                        |
| `delete`     | Delete the record                                          |
| App-specific | Custom actions like `approve`, `reject`, `close`, `assign` |

### Adding a comment[​](#adding-a-comment "Direct link to Adding a comment")

Include the `comment` field to add a comment alongside the update:

```
{
  "id": "record-guid",
  "transition": "edit",
  "comment": "<!-- html --><p>Updating per client request</p>",
  "minor_change": false
}
```

Set `minor_change: true` to suppress notifications for the update.

## Deleting records[​](#deleting-records "Direct link to Deleting records")

```
curl --request POST \
  --url "https://acme.comind.work/api/tickets/multi" \
  --header "Authorization: CMW_AUTH_CODE YOUR-TOKEN" \
  --header "Content-Type: application/json" \
  --data '[{"id": "record-guid", "transition": "delete"}]'
```

## Batch operations[​](#batch-operations "Direct link to Batch operations")

The endpoint accepts an array, so you can create, update, and delete multiple records in a single request:

```
[
  { "transition": "add", "app_alias": "TASK", "workspace_alias": "IT", "title": "Task 1" },
  { "transition": "add", "app_alias": "TASK", "workspace_alias": "IT", "title": "Task 2" },
  { "id": "existing-guid", "transition": "edit", "priority": "high" },
  { "id": "old-guid", "transition": "delete" }
]
```

The response is an array with one result per operation, in the same order.

## Field names and values[​](#field-names-and-values "Direct link to Field names and values")

The API expects internal (db) field names and values:

| What         | Format      | Example                            |
| ------------ | ----------- | ---------------------------------- |
| Field name   | db name     | `keeper_id`, `c_priority`, `state` |
| Lookup value | db value    | `"high"`, `"open"`, `"approved"`   |
| Person field | user GUID   | `"a1b2c3d4-..."`                   |
| Link field   | record GUID | `"e5f6g7h8-..."`                   |

Use `GET /api/schema/{WS}!{APP}` to discover field names and lookup values for your target app.

tip

The [MCP tools](/api-integrations/ai/mcp-tools.md) layer adds automatic resolution on top of the raw API - it accepts field captions instead of db names, lookup display values (case-insensitive), person names instead of GUIDs, and record slugs (`"IT/TASK123"`) instead of GUIDs. If you're working through MCP, these conveniences are available automatically.

## TypeScript SDK example[​](#typescript-sdk-example "Direct link to TypeScript SDK example")

Load deals over $1000, double the price, and save:

```
async function doubleBigDeals() {
  const deals = await comind.records.retrieve(
    "w/CRM/a/DEAL/tickets/list",
    { limitRecords: 1000, listOfFields: "id,title,c_amount", rlx: "c_amount>1000" }
  );

  for (const deal of deals) {
    deal.c_amount = deal.c_amount * 2;
    deal.transition = "edit";
  }

  await comind.records.save(deals);
  console.log(`Updated ${deals.length} deals`);
}
```
