companycam
# 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://gateway.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://gateway.maton.ai/companycam/v2/{resource}
```
Replace `{resource}` with the actual CompanyCam API endpoint path. The gateway 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://ctrl.maton.ai`.
### List Connections
```bash
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.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://ctrl.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://ctrl.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": "d274cf68-9e76-464c-92e3-ff274c44526e",
"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://ctrl.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://gateway.maton.ai/companycam/v2/projects')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', 'd274cf68-9e76-464c-92e3-ff274c44526e')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
If omitted, the gateway uses the default (oldest) active connection.
## 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://gateway.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://gateway.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://gateway.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://ctrl.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://gateway.maton.ai/companycam/v2/projects`
- Incorrect: `https://gateway.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)
标签
skill
ai