companycamCompanyCam 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).
Install via ClawdBot CLI:
clawdbot install byungkyu/companycamAccess the CompanyCam API with managed OAuth authentication. Manage projects, photos, users, tags, groups, documents, and webhooks for contractor photo documentation.
# 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
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.
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"
Manage your CompanyCam OAuth connections at https://ctrl.maton.ai.
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
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
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:
{
"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.
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
If you have multiple CompanyCam connections, specify which one to use with the Maton-Connection header:
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.
GET /companycam/v2/company
Returns the current company information.
GET /companycam/v2/users/current
GET /companycam/v2/users
Query parameters:
page - Page numberper_page - Results per page (default: 25)status - Filter by status (active, inactive)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 /companycam/v2/users/{id}
PUT /companycam/v2/users/{id}
Content-Type: application/json
{
"first_name": "John",
"last_name": "Smith"
}
DELETE /companycam/v2/users/{id}
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 filteringPOST /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 /companycam/v2/projects/{id}
PUT /companycam/v2/projects/{id}
Content-Type: application/json
{
"name": "Updated Project Name"
}
DELETE /companycam/v2/projects/{id}
PATCH /companycam/v2/projects/{id}/archive
PUT /companycam/v2/projects/{id}/restore
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 IDsPOST /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"]
}
GET /companycam/v2/projects/{project_id}/comments
POST /companycam/v2/projects/{project_id}/comments
Content-Type: application/json
{
"comment": {
"content": "Work completed successfully"
}
}
GET /companycam/v2/projects/{project_id}/labels
POST /companycam/v2/projects/{project_id}/labels
Content-Type: application/json
{
"labels": ["priority", "urgent"]
}
DELETE /companycam/v2/projects/{project_id}/labels/{label_id}
GET /companycam/v2/projects/{project_id}/documents
POST /companycam/v2/projects/{project_id}/documents
Content-Type: application/json
{
"uri": "https://example.com/document.pdf",
"name": "Contract.pdf"
}
GET /companycam/v2/projects/{project_id}/checklists
POST /companycam/v2/projects/{project_id}/checklists
Content-Type: application/json
{
"checklist_template_id": "template_id"
}
GET /companycam/v2/projects/{project_id}/checklists/{checklist_id}
GET /companycam/v2/projects/{project_id}/assigned_users
PUT /companycam/v2/projects/{project_id}/assigned_users/{user_id}
GET /companycam/v2/projects/{project_id}/collaborators
GET /companycam/v2/photos
Query parameters:
page - Page numberper_page - Results per pageGET /companycam/v2/photos/{id}
PUT /companycam/v2/photos/{id}
Content-Type: application/json
{
"photo": {
"captured_at": 1609459200
}
}
DELETE /companycam/v2/photos/{id}
GET /companycam/v2/photos/{id}/tags
POST /companycam/v2/photos/{id}/tags
Content-Type: application/json
{
"tags": ["exterior", "completed"]
}
GET /companycam/v2/photos/{id}/comments
POST /companycam/v2/photos/{id}/comments
Content-Type: application/json
{
"comment": {
"content": "Great progress!"
}
}
GET /companycam/v2/tags
POST /companycam/v2/tags
Content-Type: application/json
{
"display_value": "Exterior",
"color": "#FF5733"
}
GET /companycam/v2/tags/{id}
PUT /companycam/v2/tags/{id}
Content-Type: application/json
{
"display_value": "Interior",
"color": "#3498DB"
}
DELETE /companycam/v2/tags/{id}
GET /companycam/v2/groups
POST /companycam/v2/groups
Content-Type: application/json
{
"name": "Roofing Team"
}
GET /companycam/v2/groups/{id}
PUT /companycam/v2/groups/{id}
Content-Type: application/json
{
"name": "Updated Team Name"
}
DELETE /companycam/v2/groups/{id}
GET /companycam/v2/checklists
Query parameters:
page - Page numberper_page - Results per pagecompleted - Filter by completion status (true/false)GET /companycam/v2/webhooks
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.deletedGET /companycam/v2/webhooks/{id}
PUT /companycam/v2/webhooks/{id}
Content-Type: application/json
{
"url": "https://example.com/new-webhook",
"enabled": true
}
DELETE /companycam/v2/webhooks/{id}
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)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);
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']}")
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']}")
comment objectscopes parameter (not events)admin, standard, limitedcurl -g when URLs contain brackets to disable glob parsingjq, environment variables may not expand correctly. Use Python examples instead.| 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.
| 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 |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
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
companycam. For example:https://gateway.maton.ai/companycam/v2/projectshttps://gateway.maton.ai/v2/projectsAI Usage Analysis
Analysis is being generated⦠refresh in a few seconds.
Use the mcporter CLI to list, configure, auth, and call MCP servers/tools directly (HTTP or stdio), including ad-hoc servers, config edits, and CLI/type generation.
Connect to 100+ APIs (Google Workspace, Microsoft 365, GitHub, Notion, Slack, Airtable, HubSpot, etc.) with managed OAuth. Use this skill when users want to...
Build, debug, and deploy websites using HTML, CSS, JavaScript, and modern frameworks following production best practices.
YouTube Data API integration with managed OAuth. Search videos, manage playlists, access channel data, and interact with comments. Use this skill when users want to interact with YouTube. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
Scaffold, test, document, and debug REST and GraphQL APIs. Use when the user needs to create API endpoints, write integration tests, generate OpenAPI specs, test with curl, mock APIs, or troubleshoot HTTP issues.
Search for jobs across LinkedIn, Indeed, Glassdoor, ZipRecruiter, Google Jobs, Bayt, Naukri, and BDJobs using the JobSpy MCP server.