> This page is for version V1 (default).
> For other versions, use one of these documentation indexes:
> - V1 (default): https://docs.ottimate.com/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ottimate.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ottimate.com/_mcp/server.

# API Scoping & Access Control

## Data Access and API Scoping

All API integrations in Ottimate operate through **OAuth applications** tied to a specific **API User**. Understanding how data access is scoped is critical for integrations, especially in multi-company accounts.

### OAuth Apps and API Users

When you integrate with Ottimate:

1. **OAuth App** - Your integration application authenticates using Client ID and Client Secret
2. **API User** - Every OAuth app operates on behalf of an API User provisioned by Ottimate
3. **Access Scope** - The API User determines what data your integration can access

### Access Scoping Levels

API Users can be scoped at three levels:

| Scope Level        | Access                                         | Use Case                                           |
| ------------------ | ---------------------------------------------- | -------------------------------------------------- |
| **Account-level**  | All companies and locations within the account | Master integrations managing multiple subsidiaries |
| **Company-level**  | Single company and all its locations           | ERP integration for one legal entity               |
| **Location-level** | Specific location(s) only                      | Restricted integration for a single site           |

**Examples:**

**Account-Scoped API User:**

```javascript
// Can access data across all companies
GET /v1/invoices?ottimate_company_id=123  // ✅ Allowed
GET /v1/invoices?ottimate_company_id=789  // ✅ Allowed
GET /v1/vendors?ottimate_company_id=123   // ✅ Allowed
```

**Company-Scoped API User (Company 123 only):**

```javascript
// Can only access Company 123 data
GET /v1/invoices?ottimate_company_id=123  // ✅ Allowed
GET /v1/invoices?ottimate_company_id=789  // ❌ Forbidden
GET /v1/vendors?ottimate_company_id=123   // ✅ Allowed
```

**Location-Scoped API User (Location 456 only):**

```javascript
// Can only access Location 456 data
GET /v1/invoices?ottimate_location_ids=456  // ✅ Allowed
GET /v1/invoices?ottimate_location_ids=457  // ❌ Forbidden
```

---

## Resource Scoping in API Calls

Every API request that creates or retrieves data must specify the appropriate company and/or location scope.

### Company Scoping

Most API endpoints require `ottimate_company_id` to specify which company's data you're working with.

**Examples:**

```bash
# List all vendors for a specific company
GET /v1/vendors?ottimate_company_id=123

# Create a dimension for a specific company
POST /v1/dimensions
{
  "ottimate_company_id": 123,
  "erp_type": "Account",
  "ottimate_type": "account",
  "name": "Office Supplies",
  "code": "5010",
  "reference_id": "acct-office-supplies-001",
  "erp_dimension_id": "5010"
}

# List invoices for a specific company
GET /v1/invoices?ottimate_company_id=123
```

### Location Scoping

Invoices must be assigned to a specific location. Other resources (vendors, dimensions) are company-level and shared across all locations.

**Examples:**

```bash
# Create an invoice for a specific location
POST /v1/invoices
{
  "ottimate_company_id": 123,
  "ottimate_location_id": 456,
  "ottimate_vendor_id": 789,
  "invoice_number": "INV-001",
  "total_amount": 1000.00
}

# Filter invoices by location
GET /v1/invoices?ottimate_company_id=123&ottimate_location_ids=456

# Filter invoices by several locations at once (comma-separated)
GET /v1/invoices?ottimate_company_id=123&ottimate_location_ids=456,457
```

> **Warning**
>
> **Common Error:** Attempting to create an invoice with an `ottimate_location_id` that doesn't belong to the specified `ottimate_company_id` will result in a validation error.

> **Info**
>
> **Singular in bodies, plural in list filters.** Write operations take a single `ottimate_location_id` (an integer) in the request body, because an invoice belongs to exactly one location. List endpoints such as `GET /v1/invoices` take `ottimate_location_ids` (plural) — a comma-separated string, so you can filter across several locations in one call. `GET /v1/invoices/uploads` is the exception: it filters by a single `ottimate_location_id`.

### Finding the Right IDs

To determine which company and location IDs to use:

**Step 1: List all companies**

```bash
GET /v1/accounts/{account_id}/companies
```

**Step 2: List all locations**

```bash
GET /v1/accounts/{account_id}/locations
```

**Step 3: Match to your business logic**

When creating an invoice, determine which company and location it belongs to based on your business rules (e.g., which ERP it came from, which site received the goods).

---