> ## Documentation Index
> Fetch the complete documentation index at: https://vaquill.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Compare a rule across states

> Get the comparable provision in other states from one section you already have, or run one multi-state search, instead of looping a search per jurisdiction

**What this gets you:** a multi-state comparison table for any rule, built automatically instead of by hand - useful for due diligence, multi-state compliance, or any "how does this vary by state" question.

Many legal questions are really the same question asked of many jurisdictions: how does each state handle security deposits, non-competes, or breach notice?
There are three ways to answer that here, and they differ by an order of magnitude in cost.
Start at the top.

| Approach | Calls | Credits | Gives you |
| - | - | - | - |
| `GET /us/statutes/section/{actId}/cross-state` | 1 | 6 | At most one provision per state, most similar first, up to 25 states |
| `POST /us/statutes/search` with `state` as a list | 1 | 4 | One merged ranking across the states you named |
| One search per state | 1 per state | 4 per state, so 208 for 52 | A guaranteed top hit for each state, including the ones with no strong match |

**Endpoints used:** `GET /us/statutes/section/{actId}/cross-state`, `POST /us/statutes/search`, and `GET /us/statutes/coverage` (free) to check which jurisdictions carry the corpus.

## Best: start from one section you already have

If you can name the provision in one state, `cross-state` finds its analogue elsewhere.
This is the endpoint built for this question.
It returns at most one provision per state, ordered most similar first, so the response reads as a jurisdiction comparison rather than a relevance list.

<CodeGroup>
  ```bash cURL theme={"theme":"github-dark"}
  curl -G https://api.vaquill.ai/api/v1/us/statutes/section/STATE_CA_Cciv_D3_P4_T5_C2_S1950.5/cross-state \
    -H "Authorization: Bearer vq_key_..." \
    --data-urlencode "limit=10"
  ```

  ```python Python theme={"theme":"github-dark"}
  import requests

  BASE_URL = "https://api.vaquill.ai/api/v1/us"
  HEADERS = {"Authorization": "Bearer vq_key_..."}


  def cross_state(act_id: str, limit: int = 10) -> list[dict]:
      resp = requests.get(
          f"{BASE_URL}/statutes/section/{act_id}/cross-state",
          headers=HEADERS,
          params={"limit": limit},
      )
      resp.raise_for_status()
      data = resp.json()
      # Each neighbor is {"state", "similarity", "section"}, most similar first,
      # at most one per state. `statesCovered` says how many states are here.
      for n in data["neighbors"]:
          state = n["state"].upper()
          citation = n["section"]["citation"]
          print(f"{state:4} {n['similarity']:.2f}  {citation}")
      return data["neighbors"]
  ```

  ```javascript JavaScript theme={"theme":"github-dark"}
  const BASE_URL = "https://api.vaquill.ai/api/v1/us";

  async function crossState(actId, limit = 10) {
    const url = new URL(`${BASE_URL}/statutes/section/${actId}/cross-state`);
    url.searchParams.set("limit", String(limit));
    const resp = await fetch(url, {
      headers: { Authorization: "Bearer vq_key_..." },
    });
    if (!resp.ok) throw new Error(`cross-state failed: ${resp.status}`);
    const data = await resp.json();
    // data.neighbors: [{ state, similarity, section }], most similar first.
    return data.neighbors;
  }
  ```
</CodeGroup>

Take the `actId` from a `/us/statutes/search` result rather than assembling the string yourself.
Do not have one? Spend one search to find it, then one `cross-state` call.
That is two calls for a multi-state comparison against 52 for the per-jurisdiction loop.

<Warning>
  `similarity` is a retrieval score between 0 and 1 describing how closely two
  provisions read. It is not a legal opinion. A high score means the provisions
  cover the same ground, never that they impose the same obligation, and the
  differences are usually the point. Treat the response as the shortlist to read,
  not the answer.
</Warning>

A trimmed response:

```json theme={"theme":"github-dark"}
{
  "section": { "actId": "STATE_CA_Cciv_D3_P4_T5_C2_S1950.5", "citation": "Cal. Civ. Code § 1950.5" },
  "neighbors": [
    {
      "state": "ny",
      "similarity": 0.79,
      "section": { "citation": "N.Y. Gen. Oblig. Law § 7-108", "title": "..." }
    }
  ],
  "statesCovered": 1,
  "creditsConsumed": 6
}
```

`statesCovered` below the `limit` you asked for means no provision in the remaining states cleared the similarity floor.
It does not mean those states are missing from the corpus.

<Note>
  `cross-state` is scoped to state statute sections. USC, CFR, regulations and
  court rules return empty with a `note`, refunded, because a federal section has
  no state analogue by definition. `limit` caps at 25.
</Note>

## Next best: one search across several states

`state` accepts a list, so one call covers every jurisdiction you name.
Use this when you have no starting section, or when you want the corpus to pick the states rather than picking them yourself.

<CodeGroup>
  ```bash cURL theme={"theme":"github-dark"}
  curl -X POST https://api.vaquill.ai/api/v1/us/statutes/search \
    -H "Authorization: Bearer vq_key_..." \
    -H "Content-Type: application/json" \
    -d '{"query": "security deposit return deadline", "corpusType": "STATE", "state": ["ca", "ny", "tx", "fl", "wa"], "limit": 25, "fields": ["title", "excerpt", "state", "stateHtmlUrl", "htmlUrl"]}'
  ```

  ```python Python theme={"theme":"github-dark"}
  def search_states(query: str, states: list[str], limit: int = 25) -> list[dict]:
      resp = requests.post(
          f"{BASE_URL}/statutes/search",
          headers={**HEADERS, "Content-Type": "application/json"},
          json={
              "query": query,
              "corpusType": "STATE",
              "state": states,
              "limit": limit,
              # A result carries 40+ fields, most null on any row. Ask for the
              # handful the comparison table actually renders.
              "fields": ["title", "excerpt", "state", "stateHtmlUrl", "htmlUrl"],
          },
      )
      resp.raise_for_status()
      return resp.json()["results"]


  def best_per_state(results: list[dict]) -> dict[str, dict]:
      """Keep the highest-ranked hit for each state."""
      best: dict[str, dict] = {}
      for r in results:  # already in rank order
          best.setdefault(r.get("state"), r)
      return best
  ```
</CodeGroup>

One caveat that decides whether this is enough: the response is **one merged ranking**, not one slot per state.
A jurisdiction whose provision is worded unusually can be pushed off the page by five strong hits from another state.
Raise `limit` (up to 50) and group by each result's `state`, and treat a missing state as "not in the top N", not as "no such law".

<Note>
  `relevanceScore` is a relative rank within a single response. Do not compare
  scores across separate responses to decide which jurisdiction is "more
  relevant".
</Note>

## Fallback: one search per state

Loop only when you need a guaranteed slot for every named jurisdiction, including the ones with a weak match, and the visible gaps matter more than the spend.
This is one call per jurisdiction, 52 in all, against a single `cross-state` call.

<Steps>
  <Step title="Drop the states that do not carry the corpus">
    `GET /us/statutes/coverage` is free. Read it once, cache it, and never spend a
    search on a jurisdiction with no data to return.

    ```python Python theme={"theme":"github-dark"}
    def states_with_corpus(token: str = "STATE") -> list[str]:
        cov = requests.get(
            f"{BASE_URL}/statutes/coverage", headers=HEADERS
        ).json()["data"]
        return [
            j["code"]
            for j in cov["jurisdictions"]
            if j["kind"] == "state" and token in j.get("corpora", {})
        ]
    ```
  </Step>

  <Step title="Search each state and assemble the table">
    States with no match are recorded so the gaps stay visible.

    ```python Python theme={"theme":"github-dark"}
    def compare_across_states(query: str, states: list[str]) -> list[dict]:
        rows: list[dict] = []
        for state in states:
            hits = search_states(query, [state], limit=3)
            top = hits[0] if hits else None
            rows.append(
                {
                    "state": state,
                    "citation": top.get("citation") if top else None,
                    "excerpt": (top.get("excerpt") or "")[:200] if top else None,
                    # best_source_url() is the shared helper linked below.
                    "url": best_source_url(top) if top else None,
                }
            )
        return rows


    if __name__ == "__main__":
        available = set(states_with_corpus("STATE"))
        targets = [s for s in ["ca", "ny", "tx", "fl", "wa"] if s in available]
        for row in compare_across_states("security deposit return deadline", targets):
            print(f"{row['state'].upper():4}  {row['citation'] or '(no match)'}")
    ```

    Example output:

    ```text theme={"theme":"github-dark"}
    CA    Cal. Civ. Code § 1950.5
    NY    N.Y. Gen. Oblig. Law § 7-108
    TX    Tex. Prop. Code § 92.103
    ```
  </Step>
</Steps>

<Tip>
  Each result carries several optional source URL fields and any may be null. Use
  the canonical preference order in
  [Text Formats and Source URLs](/docs/api-guide/concepts/formats#picking-the-best-available-format)
  rather than writing your own, so the same section gets the same official link
  everywhere in your product.
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="Monitor corpus coverage" icon="chart-line" href="/docs/api-guide/recipes/coverage-monitoring">
    Poll for what changed since your last sync.
  </Card>

  <Card title="Enrich a citation database" icon="database" href="/docs/api-guide/recipes/citation-enrichment">
    Attach canonical citations, excerpts, and source links to a batch of rows.
  </Card>

  <Card title="Coverage matrix" icon="table-cells" href="/docs/api-guide/coverage">
    See which states carry which corpora.
  </Card>

  <Card title="Best practices" icon="circle-check" href="/docs/api-guide/best-practices">
    Scope queries, pace requests, and handle errors well.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.