CompanyCam API integration with managed OAuth. Manage projects, photos, users, tags, groups, documents, checklists, labels, collaborators, webhooks, and comp...
---
name: companycam
description: |
CompanyCam API integration with managed OAuth. Manage projects, photos, users, tags, groups, documents, checklists, labels, collaborators, webhooks, and company info for contractor photo documentation.
All write operations (create, update, delete, upload, webhook management) require explicit user approval. Webhooks send project/photo event data to external URLs — confirm the destination before creating.
Use this skill when users want to manage CompanyCam resources. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
compatibility: Requires network access and valid Maton API key
metadata:
author: maton
version: "1.0"
clawdbot:
emoji: 🧠
homepage: "https://maton.ai"
requires:
env:
- MATON_API_KEY
---
# CompanyCam
Access the CompanyCam API with managed OAuth authentication. Manage projects, photos, users, tags, groups, documents, and webhooks for contractor photo documentation.
## Quick Start
```bash
# List projects
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/companycam/v2/projects')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
## Base URL
```
https://api.maton.ai/companycam/v2/{resource}
```
Maton proxies requests to `api.companycam.com/v2` and automatically injects your OAuth token.
## Authentication
All requests require the Maton API key in the Authorization header:
```
Authorization: Bearer $MATON_API_KEY
```
**Environment Variable:** Set your API key as `MATON_API_KEY`:
```bash
export MATON_API_KEY="YOUR_API_KEY"
```
### Getting Your API Key
1. Sign in or create an account at [maton.ai](https://maton.ai)
2. Go to [maton.ai/settings](https://maton.ai/settings)
3. Copy your API key
## Connection Management
Manage your CompanyCam OAuth connections at `https://api.maton.ai`.
### List Connections
```bash
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=companycam&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
### Create Connection
```bash
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'companycam'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
### Get Connection
```bash
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
**Response:**
```json
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2026-02-12T01:56:32.259046Z",
"last_updated_time": "2026-02-12T01:57:38.944271Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "companycam",
"metadata": {}
}
}
```
Open the returned `url` in a browser to complete OAuth authorization.
### Delete Connection
```bash
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
### Specifying Connection
If you have multiple CompanyCam connections, specify which one to use with the `Maton-Connection` header:
```bash
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/companycam/v2/projects')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
If you have multiple connections, always include this header to ensure requests go to the intended account.
## Security & Permissions
- Access is scoped to projects, photos, users, tags, groups, documents, checklists, labels, collaborators, webhooks, and company info within the connected CompanyCam account.
- **All write operations require explicit user approval.** Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
- **Webhooks send data to external URLs.** Creating a webhook causes project/photo event data to be transmitted to the specified URL. Confirm the destination URL, events, and intent with the user before creating.
- **User and group management** affects account membership and access. Confirm before modifying.
## API Reference
### Company
#### Get Company
```bash
GET /companycam/v2/company
```
Returns the current company information.
### Users
#### Get Current User
```bash
GET /companycam/v2/users/current
```
#### List Users
```bash
GET /companycam/v2/users
```
Query parameters:
- `page` - Page number
- `per_page` - Results per page (default: 25)
- `status` - Filter by status (active, inactive)
#### Create User
```bash
POST /companycam/v2/users
Content-Type: application/json
{
"first_name": "John",
"last_name": "Doe",
"email_address": "john@example.com",
"user_role": "standard"
}
```
User roles: `admin`, `standard`, `limited`
#### Get User
```bash
GET /companycam/v2/users/{id}
```
#### Update User
```bash
PUT /companycam/v2/users/{id}
Content-Type: application/json
{
"first_name": "John",
"last_name": "Smith"
}
```
#### Delete User
```bash
DELETE /companycam/v2/users/{id}
```
### Projects
#### List Projects
```bash
GET /companycam/v2/projects
```
Query parameters:
- `page` - Page number
- `per_page` - Results per page (default: 25)
- `query` - Search query
- `status` - Filter by status
- `modified_since` - Unix timestamp for filtering
#### Create Project
```bash
POST /companycam/v2/projects
Content-Type: application/json
{
"name": "New Construction Project",
"address": {
"street_address_1": "123 Main St",
"city": "Los Angeles",
"state": "CA",
"postal_code": "90210",
"country": "US"
}
}
```
#### Get Project
```bash
GET /companycam/v2/projects/{id}
```
#### Update Project
```bash
PUT /companycam/v2/projects/{id}
Content-Type: application/json
{
"name": "Updated Project Name"
}
```
#### Delete Project
```bash
DELETE /companycam/v2/projects/{id}
```
#### Archive Project
```bash
PATCH /companycam/v2/projects/{id}/archive
```
#### Restore Project
```bash
PUT /companycam/v2/projects/{id}/restore
```
### Project Photos
#### List Project Photos
```bash
GET /companycam/v2/projects/{project_id}/photos
```
Query parameters:
- `page` - Page number
- `per_page` - Results per page
- `start_date` - Filter by start date (Unix timestamp)
- `end_date` - Filter by end date (Unix timestamp)
- `user_ids` - Filter by user IDs
- `group_ids` - Filter by group IDs
- `tag_ids` - Filter by tag IDs
#### Add Photo to Project
```bash
POST /companycam/v2/projects/{project_id}/photos
Content-Type: application/json
{
"uri": "https://example.com/photo.jpg",
"captured_at": 1609459200,
"coordinates": {
"lat": 34.0522,
"lon": -118.2437
},
"tags": ["exterior", "front"]
}
```
### Project Comments
#### List Project Comments
```bash
GET /companycam/v2/projects/{project_id}/comments
```
#### Add Project Comment
```bash
POST /companycam/v2/projects/{project_id}/comments
Content-Type: application/json
{
"comment": {
"content": "Work completed successfully"
}
}
```
### Project Labels
#### List Project Labels
```bash
GET /companycam/v2/projects/{project_id}/labels
```
#### Add Labels to Project
```bash
POST /companycam/v2/projects/{project_id}/labels
Content-Type: application/json
{
"labels": ["priority", "urgent"]
}
```
#### Delete Project Label
```bash
DELETE /companycam/v2/projects/{project_id}/labels/{label_id}
```
### Project Documents
#### List Project Documents
```bash
GET /companycam/v2/projects/{project_id}/documents
```
#### Upload Document
```bash
POST /companycam/v2/projects/{project_id}/documents
Content-Type: application/json
{
"uri": "https://example.com/document.pdf",
"name": "Contract.pdf"
}
```
### Project Checklists
#### List Project Checklists
```bash
GET /companycam/v2/projects/{project_id}/checklists
```
#### Create Checklist from Template
```bash
POST /companycam/v2/projects/{project_id}/checklists
Content-Type: application/json
{
"checklist_template_id": "template_id"
}
```
#### Get Project Checklist
```bash
GET /companycam/v2/projects/{project_id}/checklists/{checklist_id}
```
### Project Users
#### List Assigned Users
```bash
GET /companycam/v2/projects/{project_id}/assigned_users
```
#### Assign User to Project
```bash
PUT /companycam/v2/projects/{project_id}/assigned_users/{user_id}
```
### Project Collaborators
#### List Collaborators
```bash
GET /companycam/v2/projects/{project_id}/collaborators
```
### Photos
#### List All Photos
```bash
GET /companycam/v2/photos
```
Query parameters:
- `page` - Page number
- `per_page` - Results per page
#### Get Photo
```bash
GET /companycam/v2/photos/{id}
```
#### Update Photo
```bash
PUT /companycam/v2/photos/{id}
Content-Type: application/json
{
"photo": {
"captured_at": 1609459200
}
}
```
#### Delete Photo
```bash
DELETE /companycam/v2/photos/{id}
```
#### List Photo Tags
```bash
GET /companycam/v2/photos/{id}/tags
```
#### Add Tags to Photo
```bash
POST /companycam/v2/photos/{id}/tags
Content-Type: application/json
{
"tags": ["exterior", "completed"]
}
```
#### List Photo Comments
```bash
GET /companycam/v2/photos/{id}/comments
```
#### Add Photo Comment
```bash
POST /companycam/v2/photos/{id}/comments
Content-Type: application/json
{
"comment": {
"content": "Great progress!"
}
}
```
### Tags
#### List Tags
```bash
GET /companycam/v2/tags
```
#### Create Tag
```bash
POST /companycam/v2/tags
Content-Type: application/json
{
"display_value": "Exterior",
"color": "#FF5733"
}
```
#### Get Tag
```bash
GET /companycam/v2/tags/{id}
```
#### Update Tag
```bash
PUT /companycam/v2/tags/{id}
Content-Type: application/json
{
"display_value": "Interior",
"color": "#3498DB"
}
```
#### Delete Tag
```bash
DELETE /companycam/v2/tags/{id}
```
### Groups
#### List Groups
```bash
GET /companycam/v2/groups
```
#### Create Group
```bash
POST /companycam/v2/groups
Content-Type: application/json
{
"name": "Roofing Team"
}
```
#### Get Group
```bash
GET /companycam/v2/groups/{id}
```
#### Update Group
```bash
PUT /companycam/v2/groups/{id}
Content-Type: application/json
{
"name": "Updated Team Name"
}
```
#### Delete Group
```bash
DELETE /companycam/v2/groups/{id}
```
### Checklists
#### List All Checklists
```bash
GET /companycam/v2/checklists
```
Query parameters:
- `page` - Page number
- `per_page` - Results per page
- `completed` - Filter by completion status (true/false)
### Webhooks
#### List Webhooks
```bash
GET /companycam/v2/webhooks
```
#### Create Webhook
```bash
POST /companycam/v2/webhooks
Content-Type: application/json
{
"url": "https://example.com/webhook",
"scopes": ["project.created", "photo.created"]
}
```
Available scopes:
- `project.created`
- `project.updated`
- `project.deleted`
- `photo.created`
- `photo.updated`
- `photo.deleted`
- `document.created`
- `label.created`
- `label.deleted`
#### Get Webhook
```bash
GET /companycam/v2/webhooks/{id}
```
#### Update Webhook
```bash
PUT /companycam/v2/webhooks/{id}
Content-Type: application/json
{
"url": "https://example.com/new-webhook",
"enabled": true
}
```
#### Delete Webhook
```bash
DELETE /companycam/v2/webhooks/{id}
```
## Pagination
CompanyCam uses page-based pagination:
```bash
GET /companycam/v2/projects?page=2&per_page=25
```
Query parameters:
- `page` - Page number (default: 1)
- `per_page` - Results per page (default: 25)
## Code Examples
### JavaScript - List Projects
```javascript
const response = await fetch(
'https://api.maton.ai/companycam/v2/projects?per_page=10',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const projects = await response.json();
console.log(projects);
```
### Python - List Projects
```python
import os
import requests
response = requests.get(
'https://api.maton.ai/companycam/v2/projects',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
params={'per_page': 10}
)
projects = response.json()
for project in projects:
print(f"{project['name']}: {project['id']}")
```
### Python - Create Project with Photo
```python
import os
import requests
headers = {'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
base_url = 'https://api.maton.ai/companycam/v2'
# Create project
project_response = requests.post(
f'{base_url}/projects',
headers=headers,
json={
'name': 'Kitchen Renovation',
'address': {
'street_address_1': '456 Oak Ave',
'city': 'Denver',
'state': 'CO',
'postal_code': '80202',
'country': 'US'
}
}
)
project = project_response.json()
print(f"Created project: {project['id']}")
# Add photo to project
photo_response = requests.post(
f'{base_url}/projects/{project["id"]}/photos',
headers=headers,
json={
'uri': 'https://example.com/kitchen-before.jpg',
'tags': ['before', 'kitchen']
}
)
photo = photo_response.json()
print(f"Added photo: {photo['id']}")
```
## Notes
- Project IDs and other IDs are returned as strings
- Timestamps are Unix timestamps (seconds since epoch)
- Photos can be added via URL (uri parameter)
- Comments must be wrapped in a `comment` object
- Webhooks use `scopes` parameter (not `events`)
- User roles: `admin`, `standard`, `limited`
- IMPORTANT: When using curl commands, use `curl -g` when URLs contain brackets to disable glob parsing
- IMPORTANT: When piping curl output to `jq`, environment variables may not expand correctly. Use Python examples instead.
## Rate Limits
| Operation | Limit |
|-----------|-------|
| GET requests | 240 per minute |
| POST/PUT/DELETE | 100 per minute |
When rate limited, the API returns a 429 status code. Implement exponential backoff for retries.
## Error Handling
| Status | Meaning |
|--------|---------|
| 400 | Bad request or missing CompanyCam connection |
| 401 | Invalid or missing Maton API key |
| 404 | Resource not found |
| 422 | Validation error (check error messages) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from CompanyCam API |
### Troubleshooting: API Key Issues
1. Check that the `MATON_API_KEY` environment variable is set:
```bash
echo $MATON_API_KEY
```
2. Verify the API key is valid by listing connections:
```bash
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
### Troubleshooting: Invalid App Name
1. Ensure your URL path starts with `companycam`. For example:
- Correct: `https://api.maton.ai/companycam/v2/projects`
- Incorrect: `https://api.maton.ai/v2/projects`
## Resources
- [CompanyCam API Documentation](https://docs.companycam.com)
- [CompanyCam API Reference](https://docs.companycam.com/reference)
- [CompanyCam Getting Started](https://docs.companycam.com/docs/getting-started)
- [Maton Community](https://discord.com/invite/dBfFAcefs2)
- [Maton Support](mailto:support@maton.ai)
don't have the plugin yet? install it then click "run inline in claude" again.