On this page

Context

Code sync

The code sync routes keep a repository in the code graph. They need the fabric:codesync.write grant and a project-scoped credential, except names.

curl -sS -H "Authorization: Bearer $FABRIC_API_KEY" \
  https://fabric.wexa.ai/v1/codesync/names
{ "org_id": "org_abc", "dept_id": "dept_abc", "project_id": "proj_abc", "user_id": "user_abc" }

Parameters

ParameterTypeRequiredNotes
repo_urlstringRequiredPOST /v1/codesync/bootstrap: the clone URL, matched against the webhook payload's clone_url.
repo_namestringRequiredbootstrap: the owner/name form, matched against the payload's full_name.
ttl_secondsintegerOptionalbootstrap: how long the binding stays valid.
connector_id, nodes, edgesbodyOptionalPOST /v1/codesync/ingest-event and bulk-ingest: a client-shaped body, forwarded as sent. A body over the size cap is refused, not truncated.
job_idstringRequiredGET /v1/codesync/ingest-status/{job_id}: the job ingest-async returned. Poll on an interval; it counts against quota.
nonenames, connector and bolt-credentials take no parameters.
Errors
StatusCodeRaised when
400invalid_requestThe request body cannot be read or is not valid JSON.
403forbiddenThe credential lacks fabric:codesync.write, or has no project.
502unconfiguredNo ingestion target is configured, or no connector authority is running.
401invalid_signatureThe GitHub webhook signature is wrong or missing.
404repo_not_boundA push arrived for a repository never bootstrapped.
More details

Call connector and bootstrap before the webhook can resolve a push; the three ingest routes are alternatives, not stages.

Every route but the GitHub push receiver is project-scoped REST behind one grant. The receiver is authenticated by signature rather than by credential.

One grant gates almost all of it

GrantRoutes
fabric:codesync.writeall eight credentialled routes except GET /v1/codesync/names

The same check also requires a project-scoped credential. A token holding the grant but no project is refused with "code sync requires a project-scoped token (re-consent with a project selected)".

GET /v1/codesync/names

The identity echo. It is the one route on this page that needs no grant, and it exists so a client can discover which organization, department, project and user its credential resolves to before it starts sending data anywhere.

curl -sS -H "Authorization: Bearer $FABRIC_API_KEY" \
  https://fabric.wexa.ai/v1/codesync/names
{ "org_id": "org_abc", "dept_id": "dept_abc", "project_id": "proj_abc", "user_id": "user_abc" }

Where the platform can resolve them, the response also carries the human-readable names alongside the ids. The run quoted above could not, so only the ids came back — treat the name fields as present-when-available rather than guaranteed.

POST /v1/codesync/connector

Finds or provisions the codebase connector for the token's project, then triggers a connector synchronisation. Idempotent.

The body is empty. When the connector authority is unreachable the call fails loudly rather than half-succeeding:

{ "error": "data_service_unreachable",
  "error_description": "the connector authority refused the connection" }

POST /v1/codesync/bootstrap

Binds a repository — by URL and name — to the project's connector, and returns the binding the GitHub webhook later looks up.

curl -sS -X POST https://fabric.wexa.ai/v1/codesync/bootstrap \
  -H "Authorization: Bearer $FABRIC_API_KEY" -H "Content-Type: application/json" \
  -d '{"repo_url":"https://github.com/acme/widgets","repo_name":"acme/widgets","ttl_seconds":3600}'
FieldMeaning
repo_urlthe clone URL, matched against the webhook payload's clone_url
repo_namethe owner/name form, matched against the payload's full_name
ttl_secondshow long the binding stays valid

POST /v1/codesync/ingest-event and POST /v1/codesync/bulk-ingest

The two synchronous ingest routes. ingest-event carries one change; bulk-ingest carries a batch. Both take a client-shaped body, forward it, and return the ingestion target's JSON verbatim with its status code.

curl -sS -X POST https://fabric.wexa.ai/v1/codesync/ingest-event \
  -H "Authorization: Bearer $FABRIC_API_KEY" -H "Content-Type: application/json" \
  -d '{"connector_id":"conn_abc",
       "nodes":[{"id":"f1","kind":"File","path":"src/app.ts"}],
       "edges":[]}'
{ "ok": true, "nodes": 3, "edges": 5 }
{ "ok": true, "files": 2, "nodes": 18, "edges": 41 }

Request bodies are capped; a body over the limit is refused rather than truncated.

If the ingestion target is not configured on the deployment, these routes answer 502 with {"error":"unconfigured", ...} with a description saying the ingestion target is not set rather than pretending to have accepted the data.

POST /v1/codesync/ingest-async and GET /v1/codesync/ingest-status/{job_id}

The asynchronous pair, which is what the editor extension uses for a full extraction: a first request queues the work and returns immediately, and a second route polls it.

The payload the queue receives carries the token's organization and project, whatever the client sent. Poll on an interval, not in a tight loop: the status route counts against the project and organization quota windows.

{ "job_id": "job_abc_0001", "status": "queued" }
curl -sS -H "Authorization: Bearer $FABRIC_API_KEY" \
  https://fabric.wexa.ai/v1/codesync/ingest-status/job_abc_0001
{ "job_id": "job_abc_0001", "status": "completed", "nodes": 12, "edges": 30, "processed": 42 }

GET /v1/codesync/bolt-credentials

Returns the connection details for reading the project's graph directly, for clients that query it rather than going through the gateway.

{ "uri": "bolt://graph.example.com:7687", "username": "proj_abc",
  "password": "…", "database": "proj_abc" }

The response is a secret: do not log it, and do not cache it where a second project could read it. The values above are from a stand-in target, not a real deployment.

POST /v1/codesync/webhook/github

The GitHub push receiver. It takes no bearer token — GitHub does not hold one — and is authenticated by an HMAC-SHA256 signature over the raw request body, sent in X-Hub-Signature-256.

Four outcomes, all observed live on a gateway with the shared secret configured:

RequestResponse
X-GitHub-Event: ping, correct signature200 {"ok":true,"pong":true}
any event, wrong or missing signature401 {"error":"invalid_signature","error_description":"GitHub webhook signature mismatch"}
X-GitHub-Event: issues (or any non-push, non-ping event)200 {"ok":true,"ignored":"issues"}
X-GitHub-Event: push for a repository never bootstrapped404 {"error":"repo_not_bound","error_description":"call POST /v1/codesync/bootstrap with repo_name first, …"}

Per-route ledger

RouteResult
GET /v1/codesync/names200 with the four resolved ids
POST /v1/codesync/connector403 without the grant, 502 with it (no connector authority running)
POST /v1/codesync/bootstrap403 without the grant, 502 with it (no connector authority running)
POST /v1/codesync/ingest-event403 without the grant, 200 with it — tenant pinning observed downstream
POST /v1/codesync/bulk-ingest403 without the grant, 200 with it
POST /v1/codesync/ingest-async200, job_id returned
GET /v1/codesync/ingest-status/{job_id}200, status echoed
GET /v1/codesync/bolt-credentials403 without the grant, 200 with it
POST /v1/codesync/webhook/githuball four outcomes above, signed and unsigned

The nodes, edges and processed counts quoted depend on what your own extraction produces.

Every tool call works the same way: How every tool call works.