[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FGTHFWZPTJDNXHZPHJACEZ":3,"skill-same:01M6FGTHFWZPTJDNXHZPHJACEZ":90},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":27,"publishedAt":48,"linkOnly":49,"markdownContent":50,"markdownBody":51,"frontMatter":52,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":6,"ownerHtmlUrl":62,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":63,"install":64,"resources":77},"01M6FGTHFWZPTJDNXHZPHJACEZ","google-contacts",null,"Google Contacts API integration with managed OAuth. Manage contacts, contact groups, and search your address book.\nUse this skill when users want to create, read, update, or delete contacts, manage contact groups, or search for people in their Google account.\nFor other third party apps, use the api-gateway skill (https:\u002F\u002Fclawhub.ai\u002Fbyungkyu\u002Fapi-gateway).","kbarbel640-del\u002Fskills","kbarbel640-del","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255315490?v=4","01M6CJPPQGCCESXMG3K7BBGQ5J","01M6CJPPX2PB2BCZERFVM2C2B3",1,"MIT","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fbyungkyu\u002Fgoogle-contacts\u002FSKILL.md",[17,22],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"contacts","google contacts","google","api","people","apps","maton","api integration","manage","read","access","api-gateway","network","gateway","search","update","delete","create","valid","clawhub","2026-11-10 10:12:30",false,"---\nname: google-contacts\ndescription: |\n  Google Contacts API integration with managed OAuth. Manage contacts, contact groups, and search your address book.\n  Use this skill when users want to create, read, update, or delete contacts, manage contact groups, or search for people in their Google account.\n  For other third party apps, use the api-gateway skill (https:\u002F\u002Fclawhub.ai\u002Fbyungkyu\u002Fapi-gateway).\ncompatibility: Requires network access and valid Maton API key\nmetadata:\n  author: maton\n  version: \"1.0\"\n---\n\n# Google Contacts\n\nAccess the Google People API with managed OAuth authentication. Manage contacts, contact groups, and search your address book.\n\n## Quick Start\n\n```bash\n# List contacts\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names,emailAddresses,phoneNumbers&pageSize=10')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n## Base URL\n\n```\nhttps:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002F{native-api-path}\n```\n\nReplace `{native-api-path}` with the actual Google People API endpoint path. The gateway proxies requests to `people.googleapis.com` and automatically injects your OAuth token.\n\n## Authentication\n\nAll requests require the Maton API key in the Authorization header:\n\n```\nAuthorization: Bearer $MATON_API_KEY\n```\n\n**Environment Variable:** Set your API key as `MATON_API_KEY`:\n\n```bash\nexport MATON_API_KEY=\"YOUR_API_KEY\"\n```\n\n### Getting Your API Key\n\n1. Sign in or create an account at [maton.ai](https:\u002F\u002Fmaton.ai)\n2. Go to [maton.ai\u002Fsettings](https:\u002F\u002Fmaton.ai\u002Fsettings)\n3. Copy your API key\n\n## Connection Management\n\nManage your Google Contacts OAuth connections at `https:\u002F\u002Fctrl.maton.ai`.\n\n### List Connections\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections?app=google-contacts&status=ACTIVE')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n### Create Connection\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\ndata = json.dumps({'app': 'google-contacts'}).encode()\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections', data=data, method='POST')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nreq.add_header('Content-Type', 'application\u002Fjson')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n### Get Connection\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections\u002F{connection_id}')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n**Response:**\n```json\n{\n  \"connection\": {\n    \"connection_id\": \"21fd90f9-5935-43cd-b6c8-bde9d915ca80\",\n    \"status\": \"ACTIVE\",\n    \"creation_time\": \"2025-12-08T07:20:53.488460Z\",\n    \"last_updated_time\": \"2026-01-31T20:03:32.593153Z\",\n    \"url\": \"https:\u002F\u002Fconnect.maton.ai\u002F?session_token=...\",\n    \"app\": \"google-contacts\",\n    \"metadata\": {}\n  }\n}\n```\n\nOpen the returned `url` in a browser to complete OAuth authorization.\n\n### Delete Connection\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections\u002F{connection_id}', method='DELETE')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n### Specifying Connection\n\nIf you have multiple Google Contacts connections, specify which one to use with the `Maton-Connection` header:\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names&pageSize=10')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nreq.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\nIf omitted, the gateway uses the default (oldest) active connection.\n\n## API Reference\n\n### Contact Operations\n\n#### List Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names,emailAddresses,phoneNumbers&pageSize=100\n```\n\n**Query Parameters:**\n- `personFields` (required): Comma-separated list of fields to return (see Person Fields section)\n- `pageSize`: Number of contacts to return (max 1000, default 100)\n- `pageToken`: Token for pagination\n- `sortOrder`: `LAST_MODIFIED_ASCENDING`, `LAST_MODIFIED_DESCENDING`, `FIRST_NAME_ASCENDING`, or `LAST_NAME_ASCENDING`\n\n**Response:**\n```json\n{\n  \"connections\": [\n    {\n      \"resourceName\": \"people\u002Fc1234567890\",\n      \"names\": [{\"displayName\": \"John Doe\", \"givenName\": \"John\", \"familyName\": \"Doe\"}],\n      \"emailAddresses\": [{\"value\": \"john@example.com\"}],\n      \"phoneNumbers\": [{\"value\": \"+1-555-0123\"}]\n    }\n  ],\n  \"totalPeople\": 1,\n  \"totalItems\": 1,\n  \"nextPageToken\": \"...\"\n}\n```\n\n#### Get Contact\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002F{resourceName}?personFields=names,emailAddresses,phoneNumbers\n```\n\nUse the resource name from list or create operations (e.g., `people\u002Fc1234567890`).\n\n#### Create Contact\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002Fpeople:createContact\nContent-Type: application\u002Fjson\n\n{\n  \"names\": [{\"givenName\": \"John\", \"familyName\": \"Doe\"}],\n  \"emailAddresses\": [{\"value\": \"john@example.com\"}],\n  \"phoneNumbers\": [{\"value\": \"+1-555-0123\"}],\n  \"organizations\": [{\"name\": \"Acme Corp\", \"title\": \"Engineer\"}]\n}\n```\n\n#### Update Contact\n\n```bash\nPATCH \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002F{resourceName}:updateContact?updatePersonFields=names,emailAddresses\nContent-Type: application\u002Fjson\n\n{\n  \"etag\": \"%EgcBAgkLLjc9...\",\n  \"names\": [{\"givenName\": \"John\", \"familyName\": \"Smith\"}],\n  \"emailAddresses\": [{\"value\": \"john.smith@example.com\"}]\n}\n```\n\n**Note:** Include the `etag` from the get\u002Flist response to ensure you're updating the latest version.\n\n#### Delete Contact\n\n```bash\nDELETE \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002F{resourceName}:deleteContact\n```\n\n#### Batch Get Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople:batchGet?resourceNames=people\u002Fc123&resourceNames=people\u002Fc456&personFields=names,emailAddresses\n```\n\n#### Batch Create Contacts\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002Fpeople:batchCreateContacts\nContent-Type: application\u002Fjson\n\n{\n  \"contacts\": [\n    {\n      \"contactPerson\": {\n        \"names\": [{\"givenName\": \"Alice\", \"familyName\": \"Smith\"}],\n        \"emailAddresses\": [{\"value\": \"alice@example.com\"}]\n      }\n    },\n    {\n      \"contactPerson\": {\n        \"names\": [{\"givenName\": \"Bob\", \"familyName\": \"Jones\"}],\n        \"emailAddresses\": [{\"value\": \"bob@example.com\"}]\n      }\n    }\n  ],\n  \"readMask\": \"names,emailAddresses\"\n}\n```\n\n#### Batch Delete Contacts\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002Fpeople:batchDeleteContacts\nContent-Type: application\u002Fjson\n\n{\n  \"resourceNames\": [\"people\u002Fc123\", \"people\u002Fc456\"]\n}\n```\n\n#### Search Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople:searchContacts?query=John&readMask=names,emailAddresses\n```\n\n**Note:** Search results may have a slight delay for newly created contacts due to indexing.\n\n### Contact Group Operations\n\n#### List Contact Groups\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups?pageSize=100\n```\n\n**Response:**\n```json\n{\n  \"contactGroups\": [\n    {\n      \"resourceName\": \"contactGroups\u002Fstarred\",\n      \"groupType\": \"SYSTEM_CONTACT_GROUP\",\n      \"name\": \"starred\",\n      \"formattedName\": \"Starred\"\n    },\n    {\n      \"resourceName\": \"contactGroups\u002Fabc123\",\n      \"groupType\": \"USER_CONTACT_GROUP\",\n      \"name\": \"Work\",\n      \"formattedName\": \"Work\",\n      \"memberCount\": 5\n    }\n  ],\n  \"totalItems\": 2\n}\n```\n\n#### Get Contact Group\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\u002F{resourceName}?maxMembers=100\n```\n\nUse `contactGroups\u002Fstarred`, `contactGroups\u002Ffamily`, etc. for system groups, or the resource name for user groups.\n\n#### Create Contact Group\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\nContent-Type: application\u002Fjson\n\n{\n  \"contactGroup\": {\n    \"name\": \"Work Contacts\"\n  }\n}\n```\n\n#### Delete Contact Group\n\n```bash\nDELETE \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\u002F{resourceName}?deleteContacts=false\n```\n\nSet `deleteContacts=true` to also delete the contacts in the group.\n\n#### Batch Get Contact Groups\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups:batchGet?resourceNames=contactGroups\u002Fstarred&resourceNames=contactGroups\u002Ffamily\n```\n\n#### Modify Group Members\n\nAdd or remove contacts from a group:\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\u002F{resourceName}\u002Fmembers:modify\nContent-Type: application\u002Fjson\n\n{\n  \"resourceNamesToAdd\": [\"people\u002Fc123\", \"people\u002Fc456\"],\n  \"resourceNamesToRemove\": [\"people\u002Fc789\"]\n}\n```\n\n### Other Contacts\n\nOther contacts are people you've interacted with (e.g., via email) but haven't explicitly added to your contacts.\n\n#### List Other Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FotherContacts?readMask=names,emailAddresses&pageSize=100\n```\n\n#### Copy Other Contact to My Contacts\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002F{resourceName}:copyOtherContactToMyContactsGroup\nContent-Type: application\u002Fjson\n\n{\n  \"copyMask\": \"names,emailAddresses,phoneNumbers\"\n}\n```\n\n## Person Fields\n\nUse these fields with `personFields` or `readMask` parameters:\n\n| Field | Description |\n|-------|-------------|\n| `names` | Display name, given name, family name |\n| `emailAddresses` | Email addresses with type |\n| `phoneNumbers` | Phone numbers with type |\n| `addresses` | Postal addresses |\n| `organizations` | Company, title, department |\n| `biographies` | Bio\u002Fnotes about the person |\n| `birthdays` | Birthday information |\n| `urls` | Website URLs |\n| `photos` | Profile photos |\n| `memberships` | Contact group memberships |\n| `metadata` | Source and update information |\n\nMultiple fields: `personFields=names,emailAddresses,phoneNumbers,organizations`\n\n## Pagination\n\nUse `pageSize` and `pageToken` for pagination:\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names&pageSize=100&pageToken=NEXT_PAGE_TOKEN\n```\n\nResponse includes pagination info:\n\n```json\n{\n  \"connections\": [...],\n  \"totalPeople\": 500,\n  \"nextPageToken\": \"...\",\n  \"nextSyncToken\": \"...\"\n}\n```\n\nContinue fetching with `pageToken` until `nextPageToken` is not returned.\n\n## Code Examples\n\n### JavaScript\n\n```javascript\nconst response = await fetch(\n  'https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names,emailAddresses&pageSize=50',\n  {\n    headers: {\n      'Authorization': `Bearer ${process.env.MATON_API_KEY}`\n    }\n  }\n);\nconst data = await response.json();\n```\n\n### Python\n\n```python\nimport os\nimport requests\n\nresponse = requests.get(\n    'https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections',\n    headers={'Authorization': f'Bearer {os.environ[\"MATON_API_KEY\"]}'},\n    params={\n        'personFields': 'names,emailAddresses,phoneNumbers',\n        'pageSize': 50\n    }\n)\ndata = response.json()\n```\n\n## Notes\n\n- Resource names for contacts follow the pattern `people\u002Fc{id}` (e.g., `people\u002Fc1234567890`)\n- Resource names for contact groups follow the pattern `contactGroups\u002F{id}` (e.g., `contactGroups\u002Fabc123`)\n- System contact groups include: `starred`, `friends`, `family`, `coworkers`, `myContacts`, `all`, `blocked`\n- The `personFields` parameter is required for most read operations\n- When updating contacts, include the `etag` to prevent overwriting concurrent changes\n- Mutate requests for the same user should be sent sequentially to avoid increased latency and failures\n- IMPORTANT: When using curl commands, use `curl -g` when URLs contain brackets to disable glob parsing\n- IMPORTANT: When piping curl output to `jq` or other commands, environment variables like `$MATON_API_KEY` may not expand correctly in some shell environments\n\n## Error Handling\n\n| Status | Meaning |\n|--------|---------|\n| 400 | Missing Google Contacts connection or invalid request |\n| 401 | Invalid or missing Maton API key |\n| 403 | Permission denied (check OAuth scopes) |\n| 404 | Contact or group not found |\n| 429 | Rate limited |\n| 4xx\u002F5xx | Passthrough error from Google People API |\n\n### Troubleshooting: Invalid API Key\n\n**When you receive a \"Invalid API key\" error, ALWAYS follow these steps before concluding there is an issue:**\n\n1. Check that the `MATON_API_KEY` environment variable is set:\n\n```bash\necho $MATON_API_KEY\n```\n\n2. Verify the API key is valid by listing connections:\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n## Resources\n\n- [Google People API Overview](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest)\n- [People Resource](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest\u002Fv1\u002Fpeople)\n- [Contact Groups Resource](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest\u002Fv1\u002FcontactGroups)\n- [Person Fields Reference](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest\u002Fv1\u002Fpeople#Person)\n","# Google Contacts\n\nAccess the Google People API with managed OAuth authentication. Manage contacts, contact groups, and search your address book.\n\n## Quick Start\n\n```bash\n# List contacts\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names,emailAddresses,phoneNumbers&pageSize=10')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n## Base URL\n\n```\nhttps:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002F{native-api-path}\n```\n\nReplace `{native-api-path}` with the actual Google People API endpoint path. The gateway proxies requests to `people.googleapis.com` and automatically injects your OAuth token.\n\n## Authentication\n\nAll requests require the Maton API key in the Authorization header:\n\n```\nAuthorization: Bearer $MATON_API_KEY\n```\n\n**Environment Variable:** Set your API key as `MATON_API_KEY`:\n\n```bash\nexport MATON_API_KEY=\"YOUR_API_KEY\"\n```\n\n### Getting Your API Key\n\n1. Sign in or create an account at [maton.ai](https:\u002F\u002Fmaton.ai)\n2. Go to [maton.ai\u002Fsettings](https:\u002F\u002Fmaton.ai\u002Fsettings)\n3. Copy your API key\n\n## Connection Management\n\nManage your Google Contacts OAuth connections at `https:\u002F\u002Fctrl.maton.ai`.\n\n### List Connections\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections?app=google-contacts&status=ACTIVE')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n### Create Connection\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\ndata = json.dumps({'app': 'google-contacts'}).encode()\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections', data=data, method='POST')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nreq.add_header('Content-Type', 'application\u002Fjson')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n### Get Connection\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections\u002F{connection_id}')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n**Response:**\n```json\n{\n  \"connection\": {\n    \"connection_id\": \"21fd90f9-5935-43cd-b6c8-bde9d915ca80\",\n    \"status\": \"ACTIVE\",\n    \"creation_time\": \"2025-12-08T07:20:53.488460Z\",\n    \"last_updated_time\": \"2026-01-31T20:03:32.593153Z\",\n    \"url\": \"https:\u002F\u002Fconnect.maton.ai\u002F?session_token=...\",\n    \"app\": \"google-contacts\",\n    \"metadata\": {}\n  }\n}\n```\n\nOpen the returned `url` in a browser to complete OAuth authorization.\n\n### Delete Connection\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections\u002F{connection_id}', method='DELETE')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n### Specifying Connection\n\nIf you have multiple Google Contacts connections, specify which one to use with the `Maton-Connection` header:\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names&pageSize=10')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nreq.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\nIf omitted, the gateway uses the default (oldest) active connection.\n\n## API Reference\n\n### Contact Operations\n\n#### List Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names,emailAddresses,phoneNumbers&pageSize=100\n```\n\n**Query Parameters:**\n- `personFields` (required): Comma-separated list of fields to return (see Person Fields section)\n- `pageSize`: Number of contacts to return (max 1000, default 100)\n- `pageToken`: Token for pagination\n- `sortOrder`: `LAST_MODIFIED_ASCENDING`, `LAST_MODIFIED_DESCENDING`, `FIRST_NAME_ASCENDING`, or `LAST_NAME_ASCENDING`\n\n**Response:**\n```json\n{\n  \"connections\": [\n    {\n      \"resourceName\": \"people\u002Fc1234567890\",\n      \"names\": [{\"displayName\": \"John Doe\", \"givenName\": \"John\", \"familyName\": \"Doe\"}],\n      \"emailAddresses\": [{\"value\": \"john@example.com\"}],\n      \"phoneNumbers\": [{\"value\": \"+1-555-0123\"}]\n    }\n  ],\n  \"totalPeople\": 1,\n  \"totalItems\": 1,\n  \"nextPageToken\": \"...\"\n}\n```\n\n#### Get Contact\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002F{resourceName}?personFields=names,emailAddresses,phoneNumbers\n```\n\nUse the resource name from list or create operations (e.g., `people\u002Fc1234567890`).\n\n#### Create Contact\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002Fpeople:createContact\nContent-Type: application\u002Fjson\n\n{\n  \"names\": [{\"givenName\": \"John\", \"familyName\": \"Doe\"}],\n  \"emailAddresses\": [{\"value\": \"john@example.com\"}],\n  \"phoneNumbers\": [{\"value\": \"+1-555-0123\"}],\n  \"organizations\": [{\"name\": \"Acme Corp\", \"title\": \"Engineer\"}]\n}\n```\n\n#### Update Contact\n\n```bash\nPATCH \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002F{resourceName}:updateContact?updatePersonFields=names,emailAddresses\nContent-Type: application\u002Fjson\n\n{\n  \"etag\": \"%EgcBAgkLLjc9...\",\n  \"names\": [{\"givenName\": \"John\", \"familyName\": \"Smith\"}],\n  \"emailAddresses\": [{\"value\": \"john.smith@example.com\"}]\n}\n```\n\n**Note:** Include the `etag` from the get\u002Flist response to ensure you're updating the latest version.\n\n#### Delete Contact\n\n```bash\nDELETE \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002F{resourceName}:deleteContact\n```\n\n#### Batch Get Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople:batchGet?resourceNames=people\u002Fc123&resourceNames=people\u002Fc456&personFields=names,emailAddresses\n```\n\n#### Batch Create Contacts\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002Fpeople:batchCreateContacts\nContent-Type: application\u002Fjson\n\n{\n  \"contacts\": [\n    {\n      \"contactPerson\": {\n        \"names\": [{\"givenName\": \"Alice\", \"familyName\": \"Smith\"}],\n        \"emailAddresses\": [{\"value\": \"alice@example.com\"}]\n      }\n    },\n    {\n      \"contactPerson\": {\n        \"names\": [{\"givenName\": \"Bob\", \"familyName\": \"Jones\"}],\n        \"emailAddresses\": [{\"value\": \"bob@example.com\"}]\n      }\n    }\n  ],\n  \"readMask\": \"names,emailAddresses\"\n}\n```\n\n#### Batch Delete Contacts\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002Fpeople:batchDeleteContacts\nContent-Type: application\u002Fjson\n\n{\n  \"resourceNames\": [\"people\u002Fc123\", \"people\u002Fc456\"]\n}\n```\n\n#### Search Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople:searchContacts?query=John&readMask=names,emailAddresses\n```\n\n**Note:** Search results may have a slight delay for newly created contacts due to indexing.\n\n### Contact Group Operations\n\n#### List Contact Groups\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups?pageSize=100\n```\n\n**Response:**\n```json\n{\n  \"contactGroups\": [\n    {\n      \"resourceName\": \"contactGroups\u002Fstarred\",\n      \"groupType\": \"SYSTEM_CONTACT_GROUP\",\n      \"name\": \"starred\",\n      \"formattedName\": \"Starred\"\n    },\n    {\n      \"resourceName\": \"contactGroups\u002Fabc123\",\n      \"groupType\": \"USER_CONTACT_GROUP\",\n      \"name\": \"Work\",\n      \"formattedName\": \"Work\",\n      \"memberCount\": 5\n    }\n  ],\n  \"totalItems\": 2\n}\n```\n\n#### Get Contact Group\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\u002F{resourceName}?maxMembers=100\n```\n\nUse `contactGroups\u002Fstarred`, `contactGroups\u002Ffamily`, etc. for system groups, or the resource name for user groups.\n\n#### Create Contact Group\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\nContent-Type: application\u002Fjson\n\n{\n  \"contactGroup\": {\n    \"name\": \"Work Contacts\"\n  }\n}\n```\n\n#### Delete Contact Group\n\n```bash\nDELETE \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\u002F{resourceName}?deleteContacts=false\n```\n\nSet `deleteContacts=true` to also delete the contacts in the group.\n\n#### Batch Get Contact Groups\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups:batchGet?resourceNames=contactGroups\u002Fstarred&resourceNames=contactGroups\u002Ffamily\n```\n\n#### Modify Group Members\n\nAdd or remove contacts from a group:\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002FcontactGroups\u002F{resourceName}\u002Fmembers:modify\nContent-Type: application\u002Fjson\n\n{\n  \"resourceNamesToAdd\": [\"people\u002Fc123\", \"people\u002Fc456\"],\n  \"resourceNamesToRemove\": [\"people\u002Fc789\"]\n}\n```\n\n### Other Contacts\n\nOther contacts are people you've interacted with (e.g., via email) but haven't explicitly added to your contacts.\n\n#### List Other Contacts\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002FotherContacts?readMask=names,emailAddresses&pageSize=100\n```\n\n#### Copy Other Contact to My Contacts\n\n```bash\nPOST \u002Fgoogle-contacts\u002Fv1\u002F{resourceName}:copyOtherContactToMyContactsGroup\nContent-Type: application\u002Fjson\n\n{\n  \"copyMask\": \"names,emailAddresses,phoneNumbers\"\n}\n```\n\n## Person Fields\n\nUse these fields with `personFields` or `readMask` parameters:\n\n| Field | Description |\n|-------|-------------|\n| `names` | Display name, given name, family name |\n| `emailAddresses` | Email addresses with type |\n| `phoneNumbers` | Phone numbers with type |\n| `addresses` | Postal addresses |\n| `organizations` | Company, title, department |\n| `biographies` | Bio\u002Fnotes about the person |\n| `birthdays` | Birthday information |\n| `urls` | Website URLs |\n| `photos` | Profile photos |\n| `memberships` | Contact group memberships |\n| `metadata` | Source and update information |\n\nMultiple fields: `personFields=names,emailAddresses,phoneNumbers,organizations`\n\n## Pagination\n\nUse `pageSize` and `pageToken` for pagination:\n\n```bash\nGET \u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names&pageSize=100&pageToken=NEXT_PAGE_TOKEN\n```\n\nResponse includes pagination info:\n\n```json\n{\n  \"connections\": [...],\n  \"totalPeople\": 500,\n  \"nextPageToken\": \"...\",\n  \"nextSyncToken\": \"...\"\n}\n```\n\nContinue fetching with `pageToken` until `nextPageToken` is not returned.\n\n## Code Examples\n\n### JavaScript\n\n```javascript\nconst response = await fetch(\n  'https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections?personFields=names,emailAddresses&pageSize=50',\n  {\n    headers: {\n      'Authorization': `Bearer ${process.env.MATON_API_KEY}`\n    }\n  }\n);\nconst data = await response.json();\n```\n\n### Python\n\n```python\nimport os\nimport requests\n\nresponse = requests.get(\n    'https:\u002F\u002Fgateway.maton.ai\u002Fgoogle-contacts\u002Fv1\u002Fpeople\u002Fme\u002Fconnections',\n    headers={'Authorization': f'Bearer {os.environ[\"MATON_API_KEY\"]}'},\n    params={\n        'personFields': 'names,emailAddresses,phoneNumbers',\n        'pageSize': 50\n    }\n)\ndata = response.json()\n```\n\n## Notes\n\n- Resource names for contacts follow the pattern `people\u002Fc{id}` (e.g., `people\u002Fc1234567890`)\n- Resource names for contact groups follow the pattern `contactGroups\u002F{id}` (e.g., `contactGroups\u002Fabc123`)\n- System contact groups include: `starred`, `friends`, `family`, `coworkers`, `myContacts`, `all`, `blocked`\n- The `personFields` parameter is required for most read operations\n- When updating contacts, include the `etag` to prevent overwriting concurrent changes\n- Mutate requests for the same user should be sent sequentially to avoid increased latency and failures\n- IMPORTANT: When using curl commands, use `curl -g` when URLs contain brackets to disable glob parsing\n- IMPORTANT: When piping curl output to `jq` or other commands, environment variables like `$MATON_API_KEY` may not expand correctly in some shell environments\n\n## Error Handling\n\n| Status | Meaning |\n|--------|---------|\n| 400 | Missing Google Contacts connection or invalid request |\n| 401 | Invalid or missing Maton API key |\n| 403 | Permission denied (check OAuth scopes) |\n| 404 | Contact or group not found |\n| 429 | Rate limited |\n| 4xx\u002F5xx | Passthrough error from Google People API |\n\n### Troubleshooting: Invalid API Key\n\n**When you receive a \"Invalid API key\" error, ALWAYS follow these steps before concluding there is an issue:**\n\n1. Check that the `MATON_API_KEY` environment variable is set:\n\n```bash\necho $MATON_API_KEY\n```\n\n2. Verify the API key is valid by listing connections:\n\n```bash\npython \u003C\u003C'EOF'\nimport urllib.request, os, json\nreq = urllib.request.Request('https:\u002F\u002Fctrl.maton.ai\u002Fconnections')\nreq.add_header('Authorization', f'Bearer {os.environ[\"MATON_API_KEY\"]}')\nprint(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))\nEOF\n```\n\n## Resources\n\n- [Google People API Overview](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest)\n- [People Resource](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest\u002Fv1\u002Fpeople)\n- [Contact Groups Resource](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest\u002Fv1\u002FcontactGroups)\n- [Person Fields Reference](https:\u002F\u002Fdevelopers.google.com\u002Fpeople\u002Fapi\u002Frest\u002Fv1\u002Fpeople#Person)\n",{"name":5,"metadata":53,"description":55,"compatibility":56},{"author":34,"version":54},"1.0","Google Contacts API integration with managed OAuth. Manage contacts, contact groups, and search your address book.\nUse this skill when users want to create, read, update, or delete contacts, manage contact groups, or search for people in their Google account.\nFor other third party apps, use the api-gateway skill (https:\u002F\u002Fclawhub.ai\u002Fbyungkyu\u002Fapi-gateway).\n","Requires network access and valid Maton API key","main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fbyungkyu\u002Fgoogle-contacts",0,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del","2026-08-23 22:39:37",{"source":8,"skillName":5,"commands":65,"prompt":75,"zipAvailable":76},[66,69,72],{"tool":67,"command":68},"npx","npx skills add kbarbel640-del\u002Fskills --skill google-contacts",{"tool":70,"command":71},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill google-contacts",{"tool":73,"command":74},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill google-contacts","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fbyungkyu\u002Fgoogle-contacts\u002FSKILL.md",true,[78,84],{"path":79,"resourceType":80,"resourceTypeDesc":81,"sizeBytes":82,"sourceHtmlUrl":83},"_meta.json","REFERENCE","参考文档",462,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fbyungkyu\u002Fgoogle-contacts\u002F_meta.json",{"path":85,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":88,"sourceHtmlUrl":89},"LICENSE.txt","LICENSE","许可证",1072,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fbyungkyu\u002Fgoogle-contacts\u002FLICENSE.txt",[91,119,145,165,171,191],{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":100,"publishedAt":48},"01M6G8J55967D6281ACMKAKTEQ","crowd-prompting","A marketplace where AI agents improve prompts, system instructions, tool descriptions, and other text-based content with domain expertise from real-world operations — and earn tokens for valuable contributions.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzzadrian\u002Fcrowd-prompting\u002FSKILL.md",[97],{"categoryNo":98,"categoryName":99,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000036","内容创作者",[101,102,31,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118],"crowd prompting","prompting","with","tokens","domain","world","prompts","operations","instructions","text","tool","system","improve","productivity","marketplace","https","content","ai agents",{"skillNo":120,"name":121,"nameZh":6,"description":122,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":128,"publishedAt":48},"01M6G8J0PKPAYVET6BWE8W4C26","dilemm-ai","Compete in DilemmAI, the prisoner's dilemma AI arena at dilemm.ai. Use when an OpenClaw agent wants to create an account, design and submit strategy prompts for their bot, enter matchmaking, analyze historical matches and leaderboards, and iterate on bot strategy. Requires headless browser automation (no API available yet).","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzyori\u002Fdilemm-ai\u002FSKILL.md",[125],{"categoryNo":126,"categoryName":127,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",[129,31,130,131,132,133,45,134,135,136,137,138,139,140,141,142,143,107,144],"dilemm ai","arena","analyze","browser","openclaw agent","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking","use",{"skillNo":146,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":154,"publishedAt":48},"01M6G8HWAF3K9SW7NP3Z83CPJ6","arxiv-paper-reviews","Interact with arXiv Crawler API to fetch papers, read reviews, and submit comments. Use when working with arXiv papers, fetching paper lists by date\u002Fcategory\u002Finterest, viewing paper details with comments, or submitting paper reviews via API at http:\u002F\u002F150.158.152.82:8000.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Fweak-accept\u002FSKILL.md",[151],{"categoryNo":152,"categoryName":153,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000021","资料检索与研究",[155,156,157,158,159,160,161,103,162,142,144,37,31,163,164],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","http","via",{"skillNo":166,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":167,"categories":168,"keywords":170,"publishedAt":48},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[169],{"categoryNo":152,"categoryName":153,"taxonomyType":20,"taxonomyTypeDesc":21},[158,157,156,155,164,160,161,103,159,142,144,162,37,31,163],{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":48},"01M6G8HM95Y64JNVFC2HN4E2BG","git-summary","Get a quick summary of the current Git repository including status, recent commits, branches, and contributors.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzweack\u002Fgit-summary\u002FSKILL.md",[],[178,179,180,181,182,183,184,185,186,187,188,189,190],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":192,"name":193,"nameZh":6,"description":194,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":195,"categories":196,"keywords":201,"publishedAt":48},"01M6G8HGEGF05CNEJCGVYFSC4R","agent-constitution","Interact with AgentConstitution governance contracts on Base Sepolia. Check compliance, read rules, log actions, query governance state.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fztsalexey\u002Fagent-constitution\u002FSKILL.md",[197,198],{"categoryNo":126,"categoryName":127,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":199,"categoryName":200,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000037","律师与法务",[202,203,204,205,103,206,207,57,208,37,209,210,211,212,213,116,214,215,216],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","projects","compliance","actions","state","governance","github"]