For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Logo
DeveloperAcademyCommunityStatus
    • Overview
    • API Credentials
    • Errors
    • Legacy & Deprecated APIs
  • Events API
    • Chat Markup
    • Rate Limits
    • Message Delivery
  • (Beta) Conversations API
  • Data API
    • GETList conversations
    • GETList interactions
    • GETList plugins calls
    • GETList Plugin Resources
    • GETList Users
  • Webhook Listeners
  • Content Gateway
    • Overview
    • Integration Strategies
    • Starter Code
    • Verifying Your Build
    • Connecting Your Gateway to Moveworks
    • Authentication
    • How Permissions Work
    • Common Pitfalls
    • Operational Guide
    • Errors
    • Supported MIME Types
  • Legacy Gateways
    • Authentication
    • Response Options
    • Field Types
    • Form Gateway Errors
DeveloperAcademyCommunityStatus
On this page
  • Overview
  • Requirements
  • Running the validator
  • What it checks
  • Example output
  • If a check fails
Content Gateway

Verifying Your Build

||View as Markdown|
Was this page helpful?
Edit this page
Previous

Connecting Your Gateway to Moveworks

Next
Built with

Overview

Before connecting your gateway to Moveworks, use the validate.py script that ships with the Content Gateway Starter Code to confirm that every endpoint on your running server returns responses that conform to the Content Gateway API schema.

The validator works against any source system. It tests protocol conformance, not content. Run it against the demo server before writing any code, and again after connecting your real source.

validate.py is part of the Content Gateway Starter Code repo. If you don’t have it locally yet, clone it from github.com/moveworks/gateway and cd gateway/starter-code before running the commands below.


Requirements

  • The Content Gateway Starter Code cloned locally (contains validate.py)
  • Your gateway server must be running and reachable
  • GATEWAY_API_KEY set to the key your server expects
  • requests installed (pip install -r requirements.txt)

Running the validator

Files only: use this when your Strategy Config is set to Public to all members:

$export GATEWAY_API_KEY=<your-key>
$python validate.py

Full validation including users, groups, and permissions (use this when your Strategy Config is set to ReBAC):

$export GATEWAY_API_KEY=<your-key>
$python validate.py --rebac

Against a deployed server:

$export GATEWAY_API_KEY=<your-key>
$SERVER_URL=https://your-gateway.example.com python validate.py --rebac

What it checks

Files only (default)

CheckWhat it validates
Auth: rejects invalid keyServer returns 401 on a wrong API key
Auth: rejects missing headerServer returns 401 when no Authorization header is sent
Auth: accepts valid keyServer returns 200 with the correct key
Rate-limit headers (warn)Warns if no X-RateLimit-* (or RFC 9456 variants) headers are emitted. Advisory only. Not a failure
GET /v1/filesResponse envelope (value, @odata.context), at least one file returned
File schemaEach file has id, name, external_url, last_modified_datetime, content.mime_type; binary files have download_path (HTML body is read from /v1/files/{id}, not the list response)
GET /v1/files/{id}Single file returns correct shape and id matches; for HTML content, verifies body is inline on this endpoint

Additional checks with --rebac

CheckWhat it validates
GET /v1/files/permissions/metadataReturns model: "resource_permission" (the only supported model)
GET /v1/files/{id}/permissionsResponse has permissions array; each entry has id, type (USER or GROUP), action (VIEW)
Wildcard antipattern (warn)Warns on any {"type": "USER", "id": "*"} entries. Only {"type": "GROUP", "id": "*"} is interpreted as a wildcard. See How Permissions Work
GET /v1/usersResponse has value array; each user has id and primary_email_addr
GET /v1/groupsResponse has value array; each group has id
GET /v1/groups/{groupId}/membersEach member has id and valid type (USER or GROUP)

Example output

Run against the demo server (python content_gateway.py followed by python validate.py --rebac):

Moveworks Content Gateway: Schema Validator
════════════════════════════════════════════
Server: http://localhost:5001
Mode: ReBAC (full)
Authentication
──────────────
✓ Rejects invalid API key with 401 got HTTP 401
✓ Rejects missing Authorization header with 401 got HTTP 401
✓ Accepts valid API key got HTTP 200
⚠ No rate-limit headers found on response Moveworks reads X-RateLimit-Limit/Remaining/Reset to throttle proactively. Recommended for production.
GET /v1/files
─────────────
✓ Returns HTTP 200 got 200
✓ Response has required envelope fields (value, @odata.context)
✓ Returns at least one file got 10 files
10 file(s) returned
✓ All files have required fields and valid content shape
GET /v1/files/{id} (testing id=kb-001)
───────────────────────────────────────
✓ Returns HTTP 200 got 200
✓ File object has required fields
✓ Returned file id matches requested id requested kb-001, got kb-001
✓ text/html content includes inline body on /files/{id} Moveworks reads HTML content from this endpoint's body field, not from /files
GET /v1/files/permissions/metadata
──────────────────────────────────
✓ Returns HTTP 200 got 200
✓ Reports model='resource_permission' (the only supported model) got model='resource_permission'
GET /v1/files/{id}/permissions (testing id=kb-001)
───────────────────────────────────────────────────
✓ Returns HTTP 200 got 200
✓ Response has permissions array
✓ At least one permission entry returned got 1
✓ All permission entries have valid shape
GET /v1/users
─────────────
✓ Returns HTTP 200 got 200
✓ Returns at least one user got 5
5 user(s) returned
✓ All users have required fields (id, primary_email_addr)
GET /v1/groups
──────────────
✓ Returns HTTP 200 got 200
✓ Returns at least one group got 4
4 group(s) returned
✓ All groups have required id field
GET /v1/groups/{id}/members (testing id=group-it-staff)
────────────────────────────────────────────────────────
✓ Returns HTTP 200 got 200
2 member(s) returned
✓ All members have valid shape
════════════════════════════════════════════
✓ All checks passed

If a check fails

The validator prints exactly which field is missing or malformed. The most common causes:

SymptomLikely cause
missing fields: primary_email_addr on usersmap_item_to_user is returning email instead of primary_email_addr. Check your field mapping in Section 3
type must be USER or GROUP on permissionsfetch_permissions_for_file is returning lowercase types. Ensure values are uppercased
Permissions endpoint returns 404fetch_permissions_for_file not yet implemented; required if using ReBAC strategy
Auth check failsGATEWAY_API_KEY env var doesn’t match the key the server was started with
Wildcard antipattern warningPermission entry uses {type: USER, id: "*"} instead of {type: GROUP, id: "*"}. Only the GROUP form is recognized as a public-access wildcard by Moveworks
Rate-limit header warningNo X-RateLimit-* headers emitted on responses. Advisory only; only relevant if you enforce a rate limit on your side and want Moveworks to throttle proactively