API Guide

    Pagination, Filtering & Fields

    Keyset pagination, the fail-closed parameter policy, and trimming responses with fields.

    Keyset pagination

    List endpoints are keyset-paginated and return newest first. Pass limit, then follow the cursor:

    curl "https://api.moveitpro.com/v1/jobs?limit=100" \
      -H "Authorization: Bearer mip_live_..."
    {
      "success": true,
      "data": [ … ],
      "next_cursor": "eyJpZCI6…"
    }

    When next_cursor is present, request the next page with ?cursor=… and the same filters. When it is absent or null, you have reached the end. Keyset cursors are stable under concurrent inserts — unlike offset paging, rows are neither skipped nor duplicated while you walk a list.

    limit accepts 1–100. An out-of-range or non-integer value is rejected with 400 invalid_limit — values are never silently clamped. A corrupted cursor is 400 invalid_cursor.

    Fail-closed parameters

    Each route declares the exact parameters it accepts. Anything else — including a typo of a real parameter — is rejected:

    {
      "success": false,
      "error": "Unknown query parameter: statuss",
      "error_code": "unknown_param"
    }

    This is deliberate. A misspelled filter cannot quietly return the unfiltered set and send you a much larger, wrong answer. Sending the same parameter twice is also rejected (400 invalid_param) rather than silently answering for one of the two values.

    By-id routes accept only fields. Filters and pagination parameters on a by-id route are rejected the same way.

    Trimming responses with fields

    Pass a comma-separated allowlist to shrink each object:

    curl "https://api.moveitpro.com/v1/customers?fields=id,first_name,last_name,email" \
      -H "Authorization: Bearer mip_live_..."

    An unknown field name returns 400 invalid_fields. Field names per resource are listed in the reference, which stays in lockstep with the live gateway through parity tests.

    Caching with ETags

    Every GET returns a strong ETag header. Send it back in If-None-Match on your next poll; an unchanged response is 304 Not Modified with no body — much cheaper for everyone than re-downloading unchanged pages:

    curl "https://api.moveitpro.com/v1/customers/{id}" \
      -H "Authorization: Bearer mip_live_..." \
      -H 'If-None-Match: "…"'

    The ETag is a content hash for caching only — it is not the version token that write requests send in If-Match (that token is the record's updated_at; see Idempotency). Do not feed an ETag into If-Match.

    Common filters

    • created_after / created_before — ISO-8601 timestamps, for incremental syncs.
    • status — resource-specific status enums.
    • branch_id — available on branch-attributed resources for company-scoped keys.

    The route-by-route list of accepted parameters is authoritative in the reference; because parameters are fail-closed, guessing is never necessary.