Reference

Operations reference

Every operation family and variant with its accepted arguments, result shape, success code, HTTP status and the errors it can return.

Read as Markdown

Fifteen standard operations exist per Resource: five families (find, create, update, delete, upsert) times their variants. Which of them a given Resource and layer offers is part of its contract; the server only routes what the contract advertises. For the query language itself see Querying; for the codes see Error codes.

Over HTTP every operation is POST <api>/_resources/<Resource>/<family>/<variant> with a JSON object body of arguments. In the generated client it is avClient.<Resource>.<family>.<variant>(args, options?). Examples below use the schema User (id, email, name, role, passwordHash, createdAt, balance, meta, posts), Post (id, title, views, published, author, category) and Category.

Overview

OperationArgumentsdata on successCode, HTTPNothing matched
find.firstwhere?, orderBy?, select?/include?recordA1000, 200null, A1001, 200
find.uniquewhere (identifier), select?/include?recordA1000, 200A2003, 404
find.manywhere?, orderBy?, limit?, offset?, cursor?, select?/include?record listA1000, 200[], A1000
find.countwhere?numberA1000, 2000
create.onedata, select?/include?the created recordA1002, 201n/a
create.manydata (array), select?/include? (to-one relations only at the top level)list of created recordsA1003, 201n/a
create.countdata (array)number createdA1003, 201n/a
update.firstwhere?, orderBy?, data, select?/include?the updated recordA1004, 200null, A1001, 200
update.uniquewhere (identifier), data, select?/include?the updated recordA1004, 200A2003, 404
update.manywhere?, data, select?/include? (to-one relations only at the top level)list of updated recordsA1005, 200[], A1005
update.countwhere?, datanumber updatedA1005, 2000
delete.firstwhere?, orderBy?, select?/include?the deleted recordA1006, 200null, A1001, 200
delete.uniquewhere (identifier), select?/include?the deleted recordA1006, 200A2003, 404
delete.manynot offered with the Prisma adapterA2002, 404
delete.countwhere?number deletedA1007, 2000
upsert.uniquewhere (identifier), create, update, select?/include?the created or updated recordA1008, 200n/a

select and include are mutually exclusive (V1008). count variants take no projection. An operation with no arguments is {}. There is no take, skip or distinct: pagination is limit, offset and cursor.

Response success codes are the same in the envelope and in the HTTP status: create answers 201, everything else 200. The generated client resolves to data (and null for A1001); every other code throws. Server-side calls (framework.application..., framework.client..., framework.transaction) do the same, with the same error classes.

Argument grammar

ArgumentShapeNotes
where{ field: value | operators, AND?: [], OR?: [], NOT?: ... }A plain value is equality; null is IS NULL; keys at one level are ANDed. Relation filters: a to-one takes a nested where or null; a to-many takes some, every, none.
where (unique variants)an identifier: { id: 1 } or { email: "..." }Must match exactly one active identifier of the Resource, else V1007.
select["id", "name", { posts: { select: [...], where?, orderBy?, limit?, offset?, cursor? } }]Fields, and relations in object form to customize them. A nested "$count" reducer on a to-many relation changes its result shape. "$defaults" stands for the level's default projection (["$defaults", "email"] is the defaults plus email); valid in select only (Querying).
include["posts", "author"]Default scalars plus the named relations (default projection).
orderBy{ field: "asc" | "desc" }, an array of those, or { field: { sort, nulls: "first" | "last" } }nulls only on nullable fields that allow it.
limitnon-negative integerAt most maxListLimit (default 250).
offsetnon-negative integer
cursoran object holding exactly the ordered scalar fieldsNeeds an explicit orderBy ending in a unique tie-breaker.
data (create){ field: value, relation: { $create | $connect | $connectOrCreate } }Scalar assignments plus nested relation directives.
data (update){ field: value | { $increment | $decrement | $multiply | $divide | $push | $unset: ... }, relation: { $create | $connect | $connectOrCreate | $disconnect | $set | $update | $delete | $upsert } }
create / update (upsert)the data shapes abovecreate is used if no record matches where, else update.

Which operators, directives and relation forms a field accepts is in the contract and can be narrowed with exposure.

Wire forms of scalars: datetime is YYYY-MM-DDTHH:mm:ss.sssZ, decimal a decimal string ("10.5"), bigint an integer string, bytes base64; json is JSON as is. The generated client converts these to Date, AvDecimal, bigint and Uint8Array.

Bulk variants differ

create.many, create.count, update.many and update.count are bulk writes. With the Prisma adapter, verified:

  • No relation writes. { author: { $connect: ... } } in create.many answers V1006: Relation "author" is not writable during create. Use the foreign-key scalar (authorId) instead. In update.many / update.count relation directives answer V1006 (not writable during update).
  • Projection. select and include on create.many / update.many may name scalars and to-one relations (include: ["author"] answers 201 / 200 with the author embedded). A to-many relation at the top level is refused in either form: V1008 with Relation "posts" is not available for select. or, for include, include accepts only relations with include capability. (Relation "posts" is not available for include. in the object form). find.many, find.first and find.unique have no such limit: they accept include and select of to-one and to-many relations.
  • Nested to-many is allowed one level inside an admitted to-one relation. The bulkWrite limit applies to the top level only; beneath an admitted to-one relation the full projection is available at any depth. include: [{ "author": { "include": ["posts"] } }] (or select: ["id", { "author": { "select": ["id", { "posts": { "select": ["id", "title"] } }] } }]) is accepted, and the nested rows are read after the write, so rows created or updated by the call appear in them. A to-many at the top level stays refused.
Code
curl -X POST $BASE/_resources/Post/create/many -d '{"data":[{"title":"h2","authorId":15}],"select":["id",{"author":{"select":["id",{"posts":{"select":["id","title"]}}]}}]}'
Code
{"data":[{"id":25,"author":{"id":15,"posts":[{"id":24,"title":"h1"},{"id":25,"title":"h2"}]}}],"code":"A1003","cause":null}
  • create.count and update.count take no projection and return a number.

find

find.first

Code
curl -X POST $BASE/_resources/User/find/first -d '{"where":{"name":{"startsWith":"A"}},"select":["id","name"]}'
Code
{"data":{"id":1,"name":"Ada"},"code":"A1000","cause":null}

No match: {"data":null,"code":"A1001","cause":null}, HTTP 200 (the client resolves to null).

Errors: A2004 (V1005 unknown field, V1006 unsupported operator or order, V1008 bad projection), A2009 (V1013 nesting, V1015 too many boolean nodes).

find.unique

Code
{"where":{"email":"ada@example.com"},"select":["id","email"]}
Code
{"data":{"id":1,"email":"ada@example.com"},"code":"A1000","cause":null}

A miss is an error: 404 A2003 "No record matched the unique selector." (client: AvNotFoundError). A where that is not an identifier ({"name":"Ada"}) is 422 A2004 / V1007: Unique selector must exactly match one active identifier on Resource "User".

find.many

Code
{"where":{"role":"USER"},"orderBy":{"id":"desc"},"limit":2,"offset":1,"select":["id","email"]}
Code
{"data":[{"id":5,"email":"e@example.com"},{"id":4,"email":"d@example.com"}],"code":"A1000","cause":null}

Cursor pagination:

Code
{"orderBy":[{"id":"asc"}],"limit":2,"cursor":{"id":2},"select":["id"]}
Code
{"data":[{"id":2},{"id":3}],"code":"A1000","cause":null}

A nested to-many relation with a count:

Code
{"where":{"id":1},"select":["id",{"posts":{"select":["id","$count"],"where":{"views":{"gt":1}}}}]}
Code
{"data":[{"id":1,"posts":{"data":[{"id":2}],"count":1}}],"code":"A1000","cause":null}
Nested selectResult for that relation
["id","title"]{ id, title }[]
["$count"]{ count: number }
["id","title","$count"]{ data: { id, title }[]; count: number }

Errors: A2009 / V1014 (limit exceeds maxListLimit (250).), A2004 / V1001 (limit must be a non-negative integer.), V1009 (Cursor pagination requires an object cursor and explicit deterministic orderBy. or Cursor keys must exactly match the active ordered scalar fields.), V1005, V1006, V1008.

find.count

Code
{"where":{"role":"USER"}}
Code
{"data":5,"code":"A1000","cause":null}

create

create.one

Code
{"data":{"email":"ada@example.com","name":"Ada","role":"ADMIN","balance":"10.50","meta":{"a":1}}}
Code
{"data":{"balance":"10.5","createdAt":"2026-10-06T22:42:46.119Z","email":"ada@example.com","id":1,"meta":{"a":1},"name":"Ada","passwordHash":"","role":"ADMIN"},"code":"A1002","cause":null}

With a nested relation: {"data":{"title":"Hello","author":{"$connect":{"id":1}},"category":{"$connect":{"id":1}}}} on Post/create/one.

Errors: A2004 (V1001 wrong type, V1002 not an enum member, V1003 bad format such as createdAt: "yesterday", V1006 directive not available, V1012 bad relation action), A2008 conflict (a unique constraint: The operation conflicts with the current state of the resource.).

Omitting a required field that has no default is a validation error, one issue per missing field, at the field's path (verified, User with email and passwordHash required):

Code
// User/create/one {"data":{"name":"x"}}   -> HTTP 422
{"data":null,"code":"A2004","cause":{"message":"Operation arguments failed framework validation.","issues":[{"code":"V1000","path":["arguments","data","email"],"message":"Field \"email\" is required to create User."},{"code":"V1000","path":["arguments","data","passwordHash"],"message":"Field \"passwordHash\" is required to create User."}]}}

A BigInt outside the signed 64-bit range is V1004, also 422 A2004: "BigInt value is outside signed 64-bit range." (9223372036854775807 is accepted, 9223372036854775808 is not).

create.many

Code
{"data":[{"email":"d@example.com"}],"select":["id","email"]}
Code
{"data":[{"id":4,"email":"d@example.com"}],"code":"A1003","cause":null}

Without a projection each element is the full default record. See Bulk variants differ.

create.count

Code
{"data":[{"email":"e@example.com"}]}
Code
{"data":1,"code":"A1003","cause":null}

update

update.first

Updates the first match (in orderBy order) and returns it.

Code
{"where":{"name":null},"orderBy":{"id":"asc"},"data":{"name":"First null"},"select":["id","name"]}
Code
{"data":{"id":2,"name":"First null"},"code":"A1004","cause":null}

No match: A1001, data: null, 200.

update.unique

Code
{"where":{"id":1},"data":{"balance":{"$increment":"1.25"}},"select":["id","balance"]}
Code
{"data":{"id":1,"balance":"11.75"},"code":"A1004","cause":null}

No match: 404 A2003. Applying a directive to a field that does not offer it ({"name":{"$increment":1}}) is V1006: Mutation directive "$increment" is not available on field "name".

Nested writes and read-back in one call:

Code
{"where":{"id":1},"data":{"posts":{"$create":{"title":"nested"}}},"select":["id",{"posts":{"select":["title"],"orderBy":{"id":"desc"},"limit":1}}]}
Code
{"data":{"id":1,"posts":[{"title":"nested"}]},"code":"A1004","cause":null}

update.many

Code
{"where":{"authorId":1},"data":{"views":{"$increment":1}},"select":["id","views"]}
Code
{"data":[{"id":1,"views":1},{"id":2,"views":6}],"code":"A1005","cause":null}

update.count

Code
{"where":{"authorId":1},"data":{"published":true}}
Code
{"data":2,"code":"A1005","cause":null}

delete

delete.first

Code
{"where":{"title":"Second"},"select":["id","title"]}
Code
{"data":{"id":2,"title":"Second"},"code":"A1006","cause":null}

No match: A1001, data: null, 200.

delete.unique

Code
{"where":{"id":1}}

Returns the deleted record with A1006. Deleting it again: 404 A2003.

delete.many

Not offered with the Prisma adapter, because Prisma cannot return the deleted rows. Calling it answers 404 A2002 with V1006 at ["variant"]: Operation "delete.many" is not available on Resource "User". Use delete.count.

delete.count

Code
{"where":{"email":{"startsWith":"zz"}}}
Code
{"data":0,"code":"A1007","cause":null}

Database cascades (a Post removed with its User) happen in the database as your schema says; they are not reported separately.

upsert

upsert.unique

Code
{"where":{"email":"z@example.com"},"create":{"email":"z@example.com"},"update":{"name":"Z"},"select":["id","name"]}
Code
{"data":{"id":6,"name":"Z"},"code":"A1008","cause":null}

The same code (A1008, 200) whether it created or updated. where must be an identifier.

Errors every operation can return

CodeHTTPWhen
A2000400Malformed JSON, non-object body, missing identity headers.
A2001404The Resource is not in the contract (V1005 at ["resource"]; on an HTTP route, resource, family and variant name the URL segments).
A2002404The operation is not available on that Resource (including one removed by exposure, or delete.many). V1006 at ["family"] or ["variant"] of the request.
A2004422The arguments break a contract rule; see cause.issues.
A2005409The caller's contract hash is stale.
A2006400Unsupported protocol version.
A2009422A limit was exceeded.
A2010 / A2011 / A2012413 / 415 / 405Body too large, wrong media type, wrong method.
A3000, A3001, A3004500Unexpected failure, a database failure that is not a caller error, or a server pipe that returned invalid arguments.
A4000, A4001, A4002401, 403, 403A pipeline guard or the configuration's policy refused.

Writes can additionally return A2003 (404, a $connect to a record that does not exist), A2008 (409, a uniqueness or reference conflict), A2013 and A2014 (409, retryable concurrency outcomes: nothing was written). Full table with causes and fixes: Error codes.

See also