Upsert entity records

Changed on

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Creates or updates up to 500 records in one of the app's entities in one call, matching them to stored records by the fields you name in key.

For each record you send, a stored record with the same values in every key field is updated, and otherwise a new record is created. For example, with "key": "order_number", re-sending an order updates it instead of adding a copy, so a sync job can send the same records again safely. An update merges like Update entity record, so a field you leave out keeps its value. Only the fields the entity's schema declares are stored, so a misspelled name is left out of the record instead of failing the call. Base44 always assigns id, created_date, updated_date, created_by, and created_by_id automatically, and ignores any of them you send.

key fields must be fields the entity's schema declares as a string, number, integer or boolean, and every record needs a value for each of them. Values are compared as the schema stores them, so "42" matches a stored 42 in a number field. When two records you send share a key, the later one wins. When several stored records share a key, the newest is updated.

Row-level security applies. Only stored records the entity's rls update rule lets you change are matched, so a record you can't change gets a new copy rather than an update, and new records must be covered by the rls create rule. Every record is checked before any is written, and one that fails rejects the call. If a call fails while it's writing, some records can already be stored, and sending it again finishes the job. Wait for the first call to finish before you retry: there's no Idempotency-Key, so two calls running at once can both create the same new record.

records in the response lists the created records first, then the updated ones. Like Create entity records, this doesn't trigger the app's webhooks, automations, or workflows.

<Note>This endpoint accepts a personal API key belonging to a user with access to the app. A read-only key is refused, and workspace API keys are not accepted.</Note>

post/api/apps/{app_id}/entities/{entity_name}/upsert

Request

  • Base URL: https://app.base44.com
  • URL: https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/upsert
  • Auth: HTTP bearer

Path parameters

app_idstring required

ID of the app that owns the entity.

entity_namestring required

Name of the entity, exactly as List entity schemas reports it. Don't pass User here. It doesn't fail, but it reads and writes a separate, disconnected set of records stored under that name, not the app's real user accounts, which are managed through their own endpoints.

Request body

recordsobject[] required

The records to create or update, up to 500, each a flat JSON object of the fields the entity's schema declares. Every record needs a value for each key field.

Example request

{
  "records": [
    {
      "amount": 4200,
      "order_number": "A-1001",
      "status": "paid"
    },
    {
      "amount": 1800,
      "order_number": "A-1002",
      "status": "draft"
    }
  ]
}

Response

How many records were created and updated, and the records themselves.

createdinteger required

Number of new records created.

updatedinteger required

Number of stored records updated.

Example response

{
  "created": 1,
  "updated": 1,
  "records": [
    {
      "id": "6886b8d390dc7e2f4a2c91b4",
      "created_date": "2026-06-05T08:12:44.902000Z",
      "updated_date": "2026-06-05T08:12:44.902000Z",
      "created_by": "jane@acme.com",
      "created_by_id": "6874b0c2e1a94d0031bb77de",
      "is_sample": false,
      "order_number": "A-1002",
      "status": "draft",
      "amount": 1800
    },
    {
      "id": "6886b8d390dc7e2f4a2c91b3",
      "created_date": "2026-06-01T09:23:41.481000Z",
      "updated_date": "2026-06-05T08:12:44.915000Z",
      "created_by": "jane@acme.com",
      "created_by_id": "6874b0c2e1a94d0031bb77de",
      "is_sample": false,
      "order_number": "A-1001",
      "status": "paid",
      "amount": 4200
    }
  ]
}

Changes