文件预览

queries_and_errors.md

查看 Intuit-quickbook 技能包中的文件内容。

文件内容

queries_and_errors.md

# QuickBooks Online Query Language & Error Handling Reference

## Intuit Data Services (IDS) Query Language

### Syntax & Pagination
To retrieve lists of entities, use the SQL-like IDS Query Language.
```sql
SELECT * FROM Customer WHERE Active = true STARTPOSITION 1 MAXRESULTS 500
```
*   **Pagination:** Use `STARTPOSITION` (1-indexed) and `MAXRESULTS` (maximum limit of **1000** records per request) to paginate through large datasets.
*   **Unsupported Operators:** `OR` operations are **not** supported by the IDS query engine. Split complex `OR` conditions into separate API queries or use `IN` clauses.

### IDS-QL Injection Prevention
The QuickBooks API does not sanitize query inputs. Always escape single quotes (`'`) by replacing them with backslash-escaped single quotes (`\'`) or stripping them completely before interpolating variables into query strings:
```python
def sanitize_input(user_input: str) -> str:
    return user_input.replace("'", "\\'")
```

---

## Change Data Capture (CDC)
Query all entities of specified types that have changed since a given timestamp.
*   **Endpoint:** `/v3/company/<realmId>/cdc?entities=<EntityList>&changedSince=<Timestamp>`
*   **Example Call:** `/v3/company/12345/cdc?entities=Customer,Invoice&changedSince=2026-05-31T00:00:00Z`

---

## Error Handling & Resilience

### Common Error Codes

| Error Code | HTTP Status | Common Cause | Mitigation Strategy |
| :--- | :--- | :--- | :--- |
| **`2030`** | `400 Bad Request` | Stale `SyncToken` during update. | Fetch the latest version of the entity, merge changes, and retry. |
| **`3100`** | `400 Bad Request` | Duplicate `DocNumber`. | Enable `allowduplicatedocnum` query parameter or let system auto-generate. |
| **`3200`** | `400 Bad Request` | Transaction is locked / reconciled. | Do not allow edits via API; prompt user to unlock inside QuickBooks UI. |
| **`100`** | `401 Unauthorized` | Invalid or expired Access Token. | Execute OAuth token refresh flow and retry the request. |
| **`429`** | `429 Too Many Requests`| API rate limit exceeded (100 req/min). | Implement exponential backoff with jitter. |

### Exponential Backoff Implementation (Python)
```python
import time
import random
import requests

def execute_with_retry(api_call_func, max_retries=5):
    base_delay = 1.0  # start with 1 second
    
    for attempt in range(max_retries):
        try:
            response = api_call_func()
            if response.status_code == 200:
                return response
            elif response.status_code == 429:
                # Rate limited - backoff and retry
                delay = base_delay * (2 ** attempt) + random.uniform(0, 0.5)
                time.sleep(delay)
            else:
                response.raise_for_status()
        except requests.exceptions.RequestException as e:
            if attempt == max_retries - 1:
                raise e
            delay = base_delay * (2 ** attempt) + random.uniform(0, 0.5)
            time.sleep(delay)
```