/install 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
# List projects
python \x3C\x3C'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:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your CompanyCam OAuth connections at https://ctrl.maton.ai.
List Connections
python \x3C\x3C'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
python \x3C\x3C'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
python \x3C\x3C'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:
{
"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
python \x3C\x3C'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:
python \x3C\x3C'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
GET /companycam/v2/company
Returns the current company information.
Users
Get Current User
GET /companycam/v2/users/current
List Users
GET /companycam/v2/users
Query parameters:
page- Page numberper_page- Results per page (default: 25)status- Filter by status (active, inactive)
Create User
POST /companycam/v2/users
Content-Type: application/json
{
"first_name": "John",
"last_name": "Doe",
"email_address": "[email protected]",
"user_role": "standard"
}
User roles: admin, standard, limited
Get User
GET /companycam/v2/users/{id}
Update User
PUT /companycam/v2/users/{id}
Content-Type: application/json
{
"first_name": "John",
"last_name": "Smith"
}
Delete User
DELETE /companycam/v2/users/{id}
Projects
List Projects
GET /companycam/v2/projects
Query parameters:
page- Page numberper_page- Results per page (default: 25)query- Search querystatus- Filter by statusmodified_since- Unix timestamp for filtering
Create Project
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
GET /companycam/v2/projects/{id}
Update Project
PUT /companycam/v2/projects/{id}
Content-Type: application/json
{
"name": "Updated Project Name"
}
Delete Project
DELETE /companycam/v2/projects/{id}
Archive Project
PATCH /companycam/v2/projects/{id}/archive
Restore Project
PUT /companycam/v2/projects/{id}/restore
Project Photos
List Project Photos
GET /companycam/v2/projects/{project_id}/photos
Query parameters:
page- Page numberper_page- Results per pagestart_date- Filter by start date (Unix timestamp)end_date- Filter by end date (Unix timestamp)user_ids- Filter by user IDsgroup_ids- Filter by group IDstag_ids- Filter by tag IDs
Add Photo to Project
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
GET /companycam/v2/projects/{project_id}/comments
Add Project Comment
POST /companycam/v2/projects/{project_id}/comments
Content-Type: application/json
{
"comment": {
"content": "Work completed successfully"
}
}
Project Labels
List Project Labels
GET /companycam/v2/projects/{project_id}/labels
Add Labels to Project
POST /companycam/v2/projects/{project_id}/labels
Content-Type: application/json
{
"labels": ["priority", "urgent"]
}
Delete Project Label
DELETE /companycam/v2/projects/{project_id}/labels/{label_id}
Project Documents
List Project Documents
GET /companycam/v2/projects/{project_id}/documents
Upload Document
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
GET /companycam/v2/projects/{project_id}/checklists
Create Checklist from Template
POST /companycam/v2/projects/{project_id}/checklists
Content-Type: application/json
{
"checklist_template_id": "template_id"
}
Get Project Checklist
GET /companycam/v2/projects/{project_id}/checklists/{checklist_id}
Project Users
List Assigned Users
GET /companycam/v2/projects/{project_id}/assigned_users
Assign User to Project
PUT /companycam/v2/projects/{project_id}/assigned_users/{user_id}
Project Collaborators
List Collaborators
GET /companycam/v2/projects/{project_id}/collaborators
Photos
List All Photos
GET /companycam/v2/photos
Query parameters:
page- Page numberper_page- Results per page
Get Photo
GET /companycam/v2/photos/{id}
Update Photo
PUT /companycam/v2/photos/{id}
Content-Type: application/json
{
"photo": {
"captured_at": 1609459200
}
}
Delete Photo
DELETE /companycam/v2/photos/{id}
List Photo Tags
GET /companycam/v2/photos/{id}/tags
Add Tags to Photo
POST /companycam/v2/photos/{id}/tags
Content-Type: application/json
{
"tags": ["exterior", "completed"]
}
List Photo Comments
GET /companycam/v2/photos/{id}/comments
Add Photo Comment
POST /companycam/v2/photos/{id}/comments
Content-Type: application/json
{
"comment": {
"content": "Great progress!"
}
}
Tags
List Tags
GET /companycam/v2/tags
Create Tag
POST /companycam/v2/tags
Content-Type: application/json
{
"display_value": "Exterior",
"color": "#FF5733"
}
Get Tag
GET /companycam/v2/tags/{id}
Update Tag
PUT /companycam/v2/tags/{id}
Content-Type: application/json
{
"display_value": "Interior",
"color": "#3498DB"
}
Delete Tag
DELETE /companycam/v2/tags/{id}
Groups
List Groups
GET /companycam/v2/groups
Create Group
POST /companycam/v2/groups
Content-Type: application/json
{
"name": "Roofing Team"
}
Get Group
GET /companycam/v2/groups/{id}
Update Group
PUT /companycam/v2/groups/{id}
Content-Type: application/json
{
"name": "Updated Team Name"
}
Delete Group
DELETE /companycam/v2/groups/{id}
Checklists
List All Checklists
GET /companycam/v2/checklists
Query parameters:
page- Page numberper_page- Results per pagecompleted- Filter by completion status (true/false)
Webhooks
List Webhooks
GET /companycam/v2/webhooks
Create Webhook
POST /companycam/v2/webhooks
Content-Type: application/json
{
"url": "https://example.com/webhook",
"scopes": ["project.created", "photo.created"]
}
Available scopes:
project.createdproject.updatedproject.deletedphoto.createdphoto.updatedphoto.deleteddocument.createdlabel.createdlabel.deleted
Get Webhook
GET /companycam/v2/webhooks/{id}
Update Webhook
PUT /companycam/v2/webhooks/{id}
Content-Type: application/json
{
"url": "https://example.com/new-webhook",
"enabled": true
}
Delete Webhook
DELETE /companycam/v2/webhooks/{id}
Pagination
CompanyCam uses page-based pagination:
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
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
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
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
commentobject - Webhooks use
scopesparameter (notevents) - User roles:
admin,standard,limited - IMPORTANT: When using curl commands, use
curl -gwhen 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
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- Verify the API key is valid by listing connections:
python \x3C\x3C'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
- 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
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install companycam - 安装完成后,直接呼叫该 Skill 的名称或使用
/companycam触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
CompanyCam 是什么?
CompanyCam API integration with managed OAuth. Photo documentation platform for contractors. Use this skill when users want to manage projects, photos, users, tags, groups, or documents in CompanyCam. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 1260 次。
如何安装 CompanyCam?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install companycam」即可一键安装,无需额外配置。
CompanyCam 是免费的吗?
是的,CompanyCam 完全免费(开源免费),可自由下载、安装和使用。
CompanyCam 支持哪些平台?
CompanyCam 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 CompanyCam?
由 byungkyu(@byungkyu)开发并维护,当前版本 v1.0.0。