API Reference

REST API for building iOS and web integrations with your proposal workspace.

Base URLhttps://foundry.gitwork.co.uk

Authentication

All protected endpoints accept Authorization: Bearer <API_KEY>. Internal app pages also use a secure HttpOnly session cookie, so browser requests do not need to expose the raw key. Manage API_KEY in your Vercel project settings.

Authorization: Bearer your-api-key
Endpoints
GET/api/healthPublic

Health check — confirms the service is running.

Response
{ "ok": true, "service": "foundry-by-gitwork", "version": "0.1.0", "timestamp": "2026-03-31T00:00:00.000Z" }
GET/api/proposalsAuth required

List all proposals.

Response
{ "proposals": [{ "id": "...", "title": "...", "status": "DRAFT", "clientName": "...", "updatedAt": "..." }] }
GET/api/clientsAuth required

List manual and suggested clients in the Docs workspace.

Response
{ "clients": [{ "id": "client_acme-health", "name": "Acme Health", "slug": "acme-health", "proposalCount": 3, "source": "SUGGESTED" }, { "id": "clx...", "name": "Gitwork", "slug": "gitwork", "proposalCount": 0, "source": "MANUAL" }] }
POST/api/clientsAuth required

Create a manual client record.

Request Body (JSON)
FieldTypeDescription
namestringClient name
logoUrlstringOptional logo URL
Response
{ "client": { "id": "clx...", "name": "Gitwork", "slug": "gitwork", "proposalCount": 0, "source": "MANUAL" } }
GET/api/clients/:slugAuth required

Get a client with linked proposals and proof documents.

Path Parameters
NameTypeDescription
slugstringClient slug
Response
{ "client": { "id": "...", "name": "...", "slug": "...", "proposalCount": 3, "source": "SUGGESTED" }, "proposals": [{ "id": "...", "title": "...", "status": "DRAFT" }], "proofDocuments": [] }
PATCH/api/clients/:slugAuth required

Update a client record or promote a suggested client into a saved manual record.

Path Parameters
NameTypeDescription
slugstringClient slug
Request Body (JSON)
FieldTypeDescription
namestringUpdated client name
logoUrlstringOptional logo URL
Response
{ "client": { "id": "...", "name": "...", "slug": "...", "proposalCount": 3, "source": "MANUAL" } }
POST/api/proposalsAuth required

Create a new proposal.

Request Body (JSON)
FieldTypeDescription
titlestringProposal title
clientNamestringSuggested client name to attach to the proposal
productNamestringProduct or project name shown throughout the proposal
templateIdstringID of a template to apply
Response
{ "proposal": { "id": "...", "title": "...", "status": "DRAFT", ... } }
GET/api/proposals/:idAuth required

Get a single proposal with all sections.

Path Parameters
NameTypeDescription
idstringProposal CUID
Response
{ "proposal": { "id": "...", "title": "...", "status": "DRAFT", "cover": {...}, "engagement": {...}, "timeline": [...], "costing": {...} } }
PATCH/api/proposals/:idAuth required

Update top-level proposal fields.

Path Parameters
NameTypeDescription
idstringProposal CUID
Request Body (JSON)
FieldTypeDescription
titlestringNew title
statusDocumentStatusDRAFT | PRODUCT_SIGN_OFF | TECH_SIGN_OFF | IN_REVIEW | APPROVED | SENT | ARCHIVED
Response
{ "proposal": { "id": "...", "title": "...", "status": "...", ... } }
POST/api/proposals/:id/duplicateAuth required

Duplicate a proposal (copies all sections as a new DRAFT).

Path Parameters
NameTypeDescription
idstringSource proposal CUID
Response
{ "proposal": { "id": "...", "title": "Copy of ...", "status": "DRAFT", ... } }
POST/api/proposals/:id/archiveAuth required

Archive a proposal (sets status to ARCHIVED).

Path Parameters
NameTypeDescription
idstringProposal CUID
Response
{ "proposal": { "id": "...", "status": "ARCHIVED" } }
DELETE/api/proposals/:id/deleteAuth required

Permanently delete a proposal.

Path Parameters
NameTypeDescription
idstringProposal CUID
Response
{ "ok": true }
POST/api/proposals/:id/engagementAuth required

Update the engagement section (scope, deliverables, objectives).

Path Parameters
NameTypeDescription
idstringProposal CUID
Request Body (JSON)
FieldTypeDescription
ctasCTA[]Call-to-action buttons for the engagement section
linksLink[]Supporting links for decks, docs, routes, or email actions
Response
{ "proposal": { "id": "...", "links": [...], "ctas": [...], ... } }
POST/api/proposals/:id/timelineAuth required

Replace the timeline phases for a proposal.

Path Parameters
NameTypeDescription
idstringProposal CUID
Request Body (JSON)
FieldTypeDescription
timelinePhasesPhase[]Array of { name, duration, summary, deliverables, viewMode } objects
viewModeLIST | MILESTONEPreferred timeline presentation mode
Response
{ "proposal": { "id": "...", "timelinePhases": [...], ... } }
POST/api/proposals/:id/costingAuth required

Update costing line items for a proposal.

Path Parameters
NameTypeDescription
idstringProposal CUID
Request Body (JSON)
FieldTypeDescription
costLineItemsCostItem[]Array of costing rows with quantity, rate, and subtotal data
Response
{ "proposal": { "id": "...", "costLineItems": [...], ... } }
POST/api/proposals/:id/exportAuth required

Create an export record for print, PDF, or share-link output.

Path Parameters
NameTypeDescription
idstringProposal CUID
Request Body (JSON)
FieldTypeDescription
formatPRINT | PDF | SHARE_LINKExport format to prepare
settingsobjectOptional export settings persisted on the export record
Response
{ "export": { "id": "...", "format": "PDF", "status": "PENDING", "url": "/app/docs/:id/print", "requestedAt": "..." } }
GET/api/rate-card/peopleAuth required

List the shared People & Rates roster used by Axis and other connected clients.

Response
{ "people": [{ "id": "...", "workspaceId": "...", "seedIdentifier": "gitwork.aashir-awan", "name": "Aashir Awan", "area": "Senior • Flutter, Frontend, Backend, DevOps", "sourceRate": 1900, "sourceCurrencyCode": "USD", "billingPeriod": "MONTH", "archivedAt": null, "createdAt": "...", "updatedAt": "..." }] }

Supports optional query params `search` and `includeArchived=true`.

POST/api/rate-card/peopleAuth required

Create a new shared People & Rates roster entry.

Request Body (JSON)
FieldTypeDescription
namestringDisplay name for the person
areastringDiscipline, specialty, or role summary
sourceRatenumberStored source rate in the source currency
sourceCurrencyCodestring3-letter ISO currency code such as USD or GBP
billingPeriodDAY | WEEK | MONTHSource billing period used to interpret the stored rate
Response
{ "person": { "id": "...", "name": "New Person", "area": "Design", "sourceRate": 650, "sourceCurrencyCode": "GBP", "billingPeriod": "DAY", "archivedAt": null, "createdAt": "...", "updatedAt": "..." } }
GET/api/rate-card/people/:idAuth required

Fetch a single People & Rates roster entry.

Path Parameters
NameTypeDescription
idstringRate-card person CUID
Response
{ "person": { "id": "...", "name": "...", "area": "...", "sourceRate": 650, "sourceCurrencyCode": "GBP", "billingPeriod": "DAY", "archivedAt": null, "createdAt": "...", "updatedAt": "..." } }
PATCH/api/rate-card/people/:idAuth required

Update one or more fields on a People & Rates roster entry.

Path Parameters
NameTypeDescription
idstringRate-card person CUID
Request Body (JSON)
FieldTypeDescription
namestringUpdated display name
areastringUpdated discipline or role summary
sourceRatenumberUpdated source rate
sourceCurrencyCodestringUpdated 3-letter ISO currency code
billingPeriodDAY | WEEK | MONTHUpdated source billing period
Response
{ "person": { "id": "...", "name": "...", "area": "...", "sourceRate": 700, "sourceCurrencyCode": "USD", "billingPeriod": "WEEK", "archivedAt": null, "createdAt": "...", "updatedAt": "..." } }
DELETE/api/rate-card/people/:idAuth required

Archive a People & Rates roster entry without removing its history.

Path Parameters
NameTypeDescription
idstringRate-card person CUID
Response
{ "person": { "id": "...", "archivedAt": "2026-03-31T15:00:00.000Z", ... } }
GET/api/codeclear/statsAuth required

Get Code dashboard metrics, stage counts, re-check totals, and recent activity.

Response
{ "total": 6, "byStatus": [{ "status": "SOURCED", "count": 1 }, { "status": "CODECLEAR_COMPLETE", "count": 1 }], "avgThis": 90, "avgLast": 82, "passRateThis": 100, "recheckDue": 1, "recentActivity": [{ "id": "...", "eventType": "SCORE_FINALIZED", "createdAt": "..." }] }
GET/api/codeclear/candidatesAuth required

List developers with filters, score ranges, and facets for building the pipeline UI.

Path Parameters
NameTypeDescription
qstringSearch by name, GitHub handle, email, or stack
statusPipelineStatusFilter by sourcing / invited / assessment / verified / placed / re-check due
tierCodeClearTierFilter by Tier 1 / Tier 2 / Tier 3
identityConfidenceIdentityConfidenceFilter by HIGH / MEDIUM / LOW / PENDING
recheckDueANY | SOON | OVERDUEFilter candidates with a scheduled re-check
stackstringFilter by primary stack
sortBycreatedAt | updatedAt | name | status | recheckDueAt | overallScoreSort field
sortDirasc | descSort direction
Response
{ "items": [{ "id": "...", "name": "Sindre Sorhus", "githubHandle": "sindresorhus", "status": "CODECLEAR_COMPLETE", "tier": "TIER_1", "primaryStack": "TypeScript", "analysisState": "COMPLETE", "score": { "overallScore": 90 } }], "meta": { "page": 1, "pageSize": 20, "total": 6, "totalPages": 1, "sortBy": "updatedAt", "sortDir": "desc" }, "facets": { "stacks": ["Node.js", "React", "TypeScript"] } }
POST/api/codeclear/candidatesAuth required

Create a new developer in the shared Gitwork workspace.

Request Body (JSON)
FieldTypeDescription
namestringCandidate display name
githubHandlestringGitHub username without the leading @
primaryStackstringPrimary technical discipline or stack
emailstringEmail address
locationstringLocation
biostringShort candidate summary
tierCodeClearTierTier assignment
rateCardPersonIdstringOptional People & Rates roster link
Response
{ "candidate": { "id": "...", "name": "New Candidate", "githubHandle": "new-user", "status": "SOURCED", "tier": "TIER_1", "analysisState": "NEVER_RUN" } }
PATCH/api/codeclear/candidatesAuth required

Bulk-update developers by moving stages or flagging a re-check.

Request Body (JSON)
FieldTypeDescription
actionMOVE_STAGE | FLAG_RECHECKBulk action mode
idsstring[]Candidate IDs to update
statusPipelineStatusRequired for MOVE_STAGE
recheckDueAtISO datetimeOptional re-check due date for FLAG_RECHECK
Response
{ "candidates": [{ "id": "...", "status": "RECHECK_DUE" }] }
GET/api/codeclear/candidates/:idAuth required

Get a single developer including notes, placements, activity, scores, and GitHub runs.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Response
{ "candidate": { "id": "...", "name": "...", "score": { "overallScore": 90 }, "scoreDraft": null, "githubAnalysisRuns": [], "placements": [], "notes": [], "activityLog": [] } }
PATCH/api/codeclear/candidates/:idAuth required

Update the profile, stage, tier, optional re-check date, or People & Rates link for a developer.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Request Body (JSON)
FieldTypeDescription
namestringUpdated display name
githubHandlestringUpdated GitHub username
statusPipelineStatusUpdated pipeline stage
tierCodeClearTierUpdated tier
recheckDueAtISO datetimeRe-check date
Response
{ "candidate": { "id": "...", "status": "INVITED", "tier": "TIER_2" } }
DELETE/api/codeclear/candidates/:idAuth required

Delete a developer and its linked notes, activity, scores, runs, and placements.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Response
{ "ok": true }
POST/api/codeclear/candidates/:id/notesAuth required

Attach a note to a developer timeline.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Request Body (JSON)
FieldTypeDescription
bodystringNote content
Response
{ "note": { "id": "...", "candidateId": "...", "body": "Strong fit for platform work.", "createdBy": "Gitwork Owner", "createdAt": "..." } }
PUT/api/codeclear/candidates/:id/scoreAuth required

Finalize a score from manual review or the current draft values.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Request Body (JSON)
FieldTypeDescription
technicalDepth0-100Technical depth score
codeQuality0-100Code quality score
aiFluency0-100AI fluency score
deliveryReadiness0-100Delivery readiness score
identityConfidenceIdentityConfidenceIdentity confidence
taskScore0-100Optional task score
taskTimeSecondsnumberOptional task duration in seconds
taskAiReviewstringReviewer note
Response
{ "candidate": { "id": "...", "status": "CODECLEAR_COMPLETE", "score": { "overallScore": 86, "verifiedAt": "...", "validUntil": "..." } } }
GET/api/codeclear/candidates/:id/github-analysis/runsAuth required

List GitHub analysis runs captured for a developer.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Response
{ "runs": [{ "id": "...", "status": "COMPLETED", "analysisVersion": "docs-codeclear-v1", "startedAt": "...", "completedAt": "...", "metrics": { "averageHealthScore": 84 } }] }
POST/api/codeclear/candidates/:id/github-analysis/runsAuth required

Run a fresh public GitHub analysis and store the snapshot on the candidate.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Response
{ "run": { "id": "...", "status": "COMPLETED", "recommendedTechnicalDepth": 88, "recommendedCodeQuality": 84, "recommendedDeliveryReadiness": 80, "llmSummary": "..." }, "candidate": { "id": "...", "avatarUrl": "..." } }

Uses the candidate's `githubHandle` and optionally `GITHUB_TOKEN` for higher GitHub API limits.

POST/api/codeclear/candidates/:id/github-analysis/runs/:runId/applyAuth required

Apply a completed GitHub analysis run to the candidate's score draft.

Path Parameters
NameTypeDescription
idstringCandidate CUID
runIdstringGitHub analysis run CUID
Response
{ "candidate": { "id": "...", "scoreDraft": { "overallScore": 82, "sourceRunId": "..." } }, "run": { "id": "...", "status": "COMPLETED" } }
GET/api/codeclear/candidates/:id/scorecardAuth required

Download a generated PDF scorecard for a developer.

Path Parameters
NameTypeDescription
idstringCandidate CUID
Response
Binary PDF response

Returns `application/pdf` with a generated scorecard filename.

GET/api/templatesAuth required

List all proposal templates.

Response
{ "templates": [{ "id": "...", "name": "...", "description": "..." }] }
GET/api/proof/healthPublic

Proof service status endpoint.

Response
{ "error": "Proof service is disabled in POC mode.", "baseUrl": null }

Returns 503 until the Proof service is enabled.

GET/api/proof/documentsAuth required

Proof document API placeholder.

Response
{ "error": "Proof API is disabled in POC mode. Use the client-side draft workspace instead." }

Current GET and POST requests return 501 until the Proof service is wired back in.

Error Codes
400
Bad Request — invalid or missing fields in request body
401
Unauthorized — missing or invalid API key
404
Not Found — the requested resource does not exist
500
Internal Server Error — unexpected server-side failure
Document Statuses
DRAFT            → Initial state
PRODUCT_SIGN_OFF → Awaiting product approval
TECH_SIGN_OFF    → Awaiting technical approval
IN_REVIEW        → Under client review
APPROVED         → Approved by all parties
SENT             → Delivered to client
ARCHIVED         → Archived / no longer active