Skip to content

Composite query & includes

Two features let you fetch exactly what you need in as few round-trips as possible.

Most list and single endpoints accept ?include=a,b to embed related objects inline, resolved in one batch (no N+1). For example, a sale with its client:

curl "https://crm.h-profit.com/bapi-v2/sales?include=client&limit=10" \
  -H "Authorization: hp_live_your_key_here"
{
  "id": 4603, "amount": "…", "client_id": 105424,
  "client": { "id": 105424, "first_name": "Yaroslav", "phone": "…" }
}

An unknown include name returns 422. If a foreign key is null, the embedded value is null (for expenses — an empty array).

Relations

Resource include values
sales client
orders client, sale
shipments supplier, expenses
expenses warehouse
productions category
products images

POST /query — many resources in one call

Ask for several resources (each with its own filter, paging, field projection and includes) in a single request. Requires a valid key; each sub-query is checked against its own resource:read scope.

Request:

{
  "queries": {
    "recent_sales": {
      "resource": "sales",
      "filter": { "warehouse_id": 8562 },
      "limit": 20,
      "include": ["client"],
      "fields": ["id", "amount", "sold_at", "client"]
    },
    "catalog": {
      "resource": "products",
      "filter": { "category_id": 18726 },
      "limit": 100
    }
  }
}

Response — keyed by your alias:

{
  "success": true,
  "data": {
    "recent_sales": { "data": [ /* … */ ], "meta": { "limit": 20, "offset": 0 } },
    "catalog":      { "data": [ /* … */ ], "meta": { "limit": 100, "offset": 0 } }
  },
  "meta": { "count": 2 }
}

queries may also be an array, where each item optionally carries as (defaults to the resource name):

{ "queries": [ { "resource": "warehouses", "as": "wh" },
               { "resource": "clients", "filter": { "with_debt": 1 }, "limit": 50 } ] }

Sub-query fields

Field Meaning
resource required — one of the resources
filter object of the same filters the resource's GET accepts
limit / offset paging (limit capped at 500)
include array of relation names (relations)
fields whitelist of top-level keys to keep (id is always kept)

Error isolation

One bad sub-query never fails the batch — its slot carries an error instead of data:

{
  "success": true,
  "data": {
    "ok_one":  { "data": [ /* … */ ], "meta": { "limit": 100, "offset": 0 } },
    "bad_one": { "error": { "code": "forbidden", "message": "insufficient scope",
                            "details": { "required": ["expenses:read"] } } }
  }
}

Limits

  • At most 10 sub-queries per request.
  • Each sub-query limit is capped at 500.

Queryable resources: sales, orders, shipments, expenses, clients, categories, products, warehouses, suppliers, product_sync, productions.