Manage funding programs end-to-end on the Karma protocol: reviewers, applications, milestones, payouts, grant agreements, and AI evaluation.
Full API docs: https://gapapi.karmahq.xyz/v2/docs/static/index.html
bash
BASE_URL="${KARMA_API_URL:-https://gapapi.karmahq.xyz}"
API_KEY="${KARMA_API_KEY}"
INVOCATION_ID=$(uuidgen)
CRITICAL: Every authenticated curl call must include these headers (public endpoints like "List Community Programs" do not require x-api-key):
bash
-H "x-api-key: ${API_KEY}"
-H "X-Source: skill:funding-program-manager"
-H "X-Invocation-Id: $INVOCATION_ID"
-H "X-Skill-Version: 1.0.0"
If KARMA_API_KEY is already set, skip to Verify.
Otherwise use the AskUserQuestion tool with these options:
bash
curl -s -X POST "${BASE_URL}/v2/agent/register" \
-H "Content-Type: application/json" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{}'
Returns { "apiKey": "karma_..." } — shown only once.
Important: Always send -d '{}' — an empty body causes a 400 error.
POST ${BASE_URL}/v2/api-keys/auth/init with { "email": "..." }POST ${BASE_URL}/v2/api-keys/auth/verify with { "email": "...", "code": "...", "name": "claude-agent" }{ "key": "karma_..." }After obtaining the key, save it automatically based on the environment:
If CLAUDE_PLUGIN_DATA is set (plugin user — CLI or Cowork):
bash
mkdir -p "${CLAUDE_PLUGIN_DATA}"
echo '{"apiKey": "karma_..."}' > "${CLAUDE_PLUGIN_DATA}/credentials.json"
export KARMA_API_KEY="karma_..."
If not set (standalone CLI user): Ask to save to shell config:
bash
if [ -f "$HOME/.zshrc" ]; then SHELL_RC="$HOME/.zshrc"
elif [ -f "$HOME/.bashrc" ]; then SHELL_RC="$HOME/.bashrc"; fi
grep -q 'KARMA_API_KEY' "$SHELL_RC" 2>/dev/null && sed -i.bak 's/export KARMA_API_KEY=.*/export KARMA_API_KEY="karma_..."/' "$SHELL_RC" || echo '\n# Karma API Key\nexport KARMA_API_KEY="karma_..."' >> "$SHELL_RC"
export KARMA_API_KEY="karma_..."
bash
curl -s "${BASE_URL}/v2/agent/info" \
-H "x-api-key: ${KARMA_API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
If response includes walletAddress → ready.
Creating a program that accepts applications requires three steps:
Creates a new program in the public program registry.
bash
curl -s -X POST "${BASE_URL}/v2/program-registry" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"metadata": {
"title": "My Grants Program",
"description": "Fund public goods builders...",
"communityRef": "COMMUNITY_UID",
"socialLinks": { "grantsSite": "https://example.com/apply" },
"adminEmails": ["admin@example.com"],
"financeEmails": ["finance@example.com"],
"currency": "USDC",
"programBudget": "500000",
"startsAt": "2026-04-01",
"endsAt": "2026-12-31"
},
"type": "grant",
"deadline": "2026-06-30",
"submissionUrl": "https://example.com/apply"
}'
ParamRequiredDescriptionmetadata.titleYesProgram namemetadata.descriptionYesProgram descriptionmetadata.communityRefYesCommunity UID (string or array)metadata.socialLinks.grantsSiteYesURL to the grants/application sitemetadata.adminEmailsYes (for community admins)Admin contact emailsmetadata.financeEmailsYes (for community admins)Finance contact emailsmetadata.currencyNoFunding currency (e.g. "USDC", "OP")metadata.programBudgetNoTotal budget amountmetadata.shortDescriptionNoShort summary (max 100 chars)metadata.startsAtNoProgram start datemetadata.endsAtNoProgram end datemetadata.anyoneCanJoinNoWhether anyone can applymetadata.invoiceRequiredNoWhether invoice is requiredtypeNogrant (default), hackathon, bounty, accelerator, vc_fund, rfp``deadlineNoApplication deadline (date string)submissionUrlNoExternal application URLchainIDNoBlockchain ID
Returns the created program with programId. Save it for the next steps.
When the user wants to create a program, present the required and key optional fields:
To create your funding program, I'll need the following. Title, description, community, grants site URL, and contact emails are required:
- Title: Program name
- Description: What does this program fund?
- Community: Which community is this for?
- Grants Site URL: Where do applicants go?
- Admin Emails: Admin contact email(s)
- Finance Emails: Finance contact email(s)
- Type: Grant / Hackathon / Bounty / Accelerator / VC Fund / RFP (default: Grant)
- Budget: Total program budget
- Currency: Funding currency (e.g. USDC, OP)
- Deadline: Application deadline
- Start / End Dates: Program duration
After the program exists in the registry, create its funding configuration to enable application management.
bash
curl -s -X POST "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"isEnabled": true,
"formSchema": null,
"reviewers": []
}'
ParamRequiredDescriptionisEnabledNoEnable applications (default: false)formSchemaNoIntake form schema (null = no form yet, configure in Step 3)postApprovalFormSchemaNoPost-approval form schemakycFormUrlNoKYC form URLkybFormUrlNoKYB form URLreviewersNoInitial reviewers array
Define the fields applicants must fill out. The form must contain at least one email field.
bash
curl -s -X PUT "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"formSchema": {
"fields": [
{
"id": "field_email",
"label": "Contact Email",
"type": "email",
"required": true,
"placeholder": "your@email.com"
},
{
"id": "field_project_name",
"label": "Project Name",
"type": "text",
"required": true,
"placeholder": "Your project name"
},
{
"id": "field_description",
"label": "Project Description",
"type": "textarea",
"required": true,
"description": "Describe what your project does and its impact"
},
{
"id": "field_funding_amount",
"label": "Requested Funding",
"type": "number",
"required": true,
"placeholder": "50000"
},
{
"id": "field_category",
"label": "Category",
"type": "select",
"required": false,
"options": [
{ "value": "defi", "label": "DeFi" },
{ "value": "infrastructure", "label": "Infrastructure" },
{ "value": "public-goods", "label": "Public Goods" }
]
}
]
}
}'
Each field in formSchema.fields:
PropertyRequiredDescriptionidYesUnique field ID (e.g. field_email, field_name)labelYesDisplay label — also used as key in application datatypeYestext, textarea, number, email, url, select``requiredNoWhether the field is mandatory (default: false)placeholderNoPlaceholder textdescriptionNoHelp text shown below the fieldoptionsFor selectArray of { value, label }
Important: The form must include at least one email type field for application tracking.
Your program is live and ready to accept applications!
- Program: {title}
- Program ID: {programId}
- Applications: {isEnabled ? "Enabled" : "Disabled"}
- Form Fields: {fieldCount} fields configured
Next steps: Add reviewers, or share the application link with potential applicants.
bash
curl -s "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s "${BASE_URL}/v2/funding-program-configs/community/${COMMUNITY_UID}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
No auth required — public endpoint.
Update program metadata in the program registry.
bash
curl -s -X PUT "${BASE_URL}/v2/program-registry/${PROGRAM_ID}" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"metadata": {
"title": "Updated Program Name",
"description": "Updated description...",
"communityRef": "COMMUNITY_UID",
"socialLinks": { "grantsSite": "https://example.com/apply" }
}
}'
Important: Fetch current program details first and merge changes — the update replaces metadata fields.
Update the funding configuration (enable/disable applications, update forms).
bash
curl -s -X PUT "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"isEnabled": true,
"formSchema": { ... },
"postApprovalFormSchema": { ... }
}'
bash
curl -s "${BASE_URL}/v2/funding-applications/program/${PROGRAM_ID}/statistics" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s "${BASE_URL}/v2/funding-applications/program/${PROGRAM_ID}?page=1&limit=20&status=${STATUS}&search=${SEARCH}&sortBy=createdAt&sortOrder=desc" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
Query params (all optional):
ParamValuesstatus``pending, under_review, approved, rejected, revision_requested, resubmitted``searchSearch by email, reference number, or project titlesortBy``createdAt, updatedAt, status, applicantEmail, referenceNumber, projectTitle, aiEvaluationScore``sortOrder``asc, desc``pagePage number (default: 1)limitItems per page (default: 20, max: 100)
bash
curl -s "${BASE_URL}/v2/funding-applications/${REFERENCE_NUMBER}" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
Reference number format: APP-XXXXX-XXXXX
bash
curl -s -X PUT "${BASE_URL}/v2/funding-applications/${REFERENCE_NUMBER}/status" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"status": "approved",
"reason": "Strong proposal with clear milestones",
"approvedAmount": "50000",
"approvedCurrency": "USDC"
}'
ParamRequiredDescriptionstatusYespending, under_review, approved, rejected, revision_requested``reasonNoReason for the status changeapprovedAmountWhen approvingAmount approved (positive number as string)approvedCurrencyWhen approvingCurrency (e.g. "USDC", "OP", "USD")
Applying requires knowing the program's form fields first. Always fetch the form schema before asking the user for input.
bash
curl -s "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
Look at applicationConfig.formSchema.fields in the response. Each field has:
PropertyDescriptionidInternal field IDlabelDisplay label — use this as the key in applicationDatatype``text, textarea, number, email, url, select``requiredWhether the field must be filledplaceholderHint textdescriptionHelp textoptionsFor select fields: [{ value, label }]
Skip fields with deleted: true.
Present the form fields to the user and collect their answers. Example prompt:
To apply to {programName}, please provide the following:
- Project Name (required): Your project's name
- Description (required): What does your project do?
- Funding Amount: How much are you requesting?
- Team Size: Number of team members
You'll also need your email address for application tracking.
Check if the program has real-time AI evaluation enabled by looking at applicationConfig.formSchema.aiConfig.enableRealTimeEvaluation in the program config from Step 1.
If enabled, call the evaluate-realtime endpoint with the user's answers:
bash
curl -s -X POST "${BASE_URL}/v2/funding-applications/${PROGRAM_ID}/evaluate-realtime" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"applicationData": {
"Project Name": "My DeFi Protocol",
"Description": "A decentralized lending platform..."
}
}'
Response:
json
{
"success": true,
"data": { "score": 8, "decision": "approve", "strengths": [...], "concerns": [...] },
"promptId": "prompt-123"
}
Show the AI feedback to the user:
AI Feedback (score: {score}/10 — {decision})
Strengths: {strengths} Concerns: {concerns}
This AI review is for guidance only and may not be fully accurate.
Would you like to revise your answers or proceed to submit?
If the user wants to revise, go back to Step 2. If they want to proceed, save the evaluation for Step 5.
If not enabled or evaluation fails: Skip this step — the user can still submit without AI feedback.
Some programs require an access code. Check if applicationConfig.formSchema.settings.accessCode exists in the program config. If so, ask the user for it and validate:
bash
curl -s -X POST "${BASE_URL}/v2/funding-applications/${PROGRAM_ID}/validate-access-code" \
-H "Content-Type: application/json" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{ "accessCode": "user-provided-code" }'
No auth required for validation.
IMPORTANT: The applicationData keys must be the field labels (not field IDs). This matches how the frontend stores form data.
If AI evaluation was performed in Step 3, include the aiEvaluation field with the stringified result:
bash
curl -s -X POST "${BASE_URL}/v2/funding-applications/${PROGRAM_ID}" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"applicantEmail": "applicant@example.com",
"applicationData": {
"Project Name": "My DeFi Protocol",
"Description": "A decentralized lending platform...",
"Funding Amount": "50000",
"Team Size": "5"
},
"aiEvaluation": {
"evaluation": "{\"score\": 8, \"decision\": \"approve\", ...}",
"promptId": "prompt-123"
},
"accessCode": "optional-code"
}'
ParamRequiredDescriptionapplicantEmailYesApplicant's email (used for notifications)applicationDataYesForm responses keyed by field labelaiEvaluationNo{ evaluation: "<stringified result>", promptId } from Step 3accessCodeIf gatedAccess code for gated programs
Response (201 Created):
json
{
"referenceNumber": "APP-ABCD1234-XYZ789",
"status": "pending",
"programId": "...",
"applicantEmail": "applicant@example.com",
"createdAt": "2024-01-01T00:00:00Z"
}
After submission:
Your application has been submitted!
- Reference: {referenceNumber}
- Program: {programName}
- Status: Pending
You'll receive updates at {applicantEmail}.
bash
curl -s "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}/reviewers" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s -X POST "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}/reviewers" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"name": "Alice Smith",
"email": "alice@example.com",
"telegram": "@alice_reviews"
}'
bash
curl -s -X DELETE "${BASE_URL}/v2/funding-program-configs/${PROGRAM_ID}/reviewers/by-email" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{ "email": "alice@example.com" }'
bash
curl -s "${BASE_URL}/v2/programs/${PROGRAM_ID}/milestone-reviewers" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s -X POST "${BASE_URL}/v2/programs/${PROGRAM_ID}/milestone-reviewers" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"name": "Bob Jones",
"email": "bob@example.com",
"telegram": "@bob_milestones"
}'
bash
curl -s -X DELETE "${BASE_URL}/v2/programs/${PROGRAM_ID}/milestone-reviewers/by-email" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{ "email": "bob@example.com" }'
bash
curl -s -X PUT "${BASE_URL}/v2/funding-applications/${REFERENCE_NUMBER}/reviewers" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"appReviewerAddresses": ["0x1234..."],
"milestoneReviewerAddresses": ["0x5678..."]
}'
Both arrays are optional — provide at least one. Addresses must be valid Ethereum addresses (lowercase).
bash
curl -s "${BASE_URL}/v2/funding-applications/${REFERENCE_NUMBER}/milestone-completions" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
Returns completions with isVerified, verifiedBy, verifiedAt, and verificationComment fields.
bash
curl -s -X POST "${BASE_URL}/v2/payouts/disburse" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"communityUID": "community-uid",
"chainID": 10,
"safeAddress": "0xsafe...",
"token": "USDC",
"tokenAddress": "0xtoken...",
"tokenDecimals": 6,
"grants": [
{
"grantUID": "grant-uid",
"projectUID": "project-uid",
"amount": "5000",
"payoutAddress": "0xrecipient..."
}
]
}'
All addresses must be valid Ethereum addresses (lowercase, 0x + 40 hex chars).
bash
curl -s "${BASE_URL}/v2/payouts/grant/${GRANT_UID}/history?page=1&limit=20" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s "${BASE_URL}/v2/payouts/grant/${GRANT_UID}/total-disbursed" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s "${BASE_URL}/v2/payouts/community/${COMMUNITY_UID}/pending?page=1&limit=20" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s "${BASE_URL}/v2/payouts/safe/${SAFE_ADDRESS}/awaiting?page=1&limit=20" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s "${BASE_URL}/v2/grant-agreements/${GRANT_UID}" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s -X POST "${BASE_URL}/v2/grant-agreements/${GRANT_UID}" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"signed": true,
"communityUID": "community-uid"
}'
bash
curl -s -X POST "${BASE_URL}/v2/funding-applications/${REFERENCE_NUMBER}/evaluate" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
No request body — evaluation uses the application's existing data.
bash
curl -s -X POST "${BASE_URL}/v2/funding-applications/${REFERENCE_NUMBER}/evaluate-internal" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
Internal evaluations are only visible to program admins.
bash
curl -s "${BASE_URL}/v2/applications/${REFERENCE_NUMBER}/comments?admin=true" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0"
bash
curl -s -X POST "${BASE_URL}/v2/applications/${REFERENCE_NUMBER}/comments" \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "X-Source: skill:funding-program-manager" -H "X-Invocation-Id: $INVOCATION_ID" -H "X-Skill-Version: 1.0.0" \
-d '{
"content": "This application looks promising. Strong team and clear deliverables.",
"authorName": "Program Admin"
}'
ParamRequiredDescriptioncontentYesComment text (1-10000 chars)authorNameNoDisplay name (max 100 chars)
User saysAction"create a program", "new funding program", "set up a grants program"Create program in registry → create funding config → configure intake form"configure intake form", "add form fields", "set up application form"Configure intake form fields"update program", "rename program", "change program description"Update program in registry (fetch current details first, merge changes)"enable applications", "disable applications"Update funding config isEnabled"list reviewers", "who reviews this program"List program reviewers"add reviewer", "invite reviewer"Add program reviewer"remove reviewer"Remove program reviewer by email"list milestone reviewers"List milestone reviewers"add milestone reviewer"Add milestone reviewer"remove milestone reviewer"Remove milestone reviewer"assign reviewers to application"Assign application reviewers"apply to program", "submit application", "apply for grant"Get form → collect answers → AI feedback → submit"what fields does this program need"Get program application form schema"get AI feedback", "score my application", "evaluate my draft"Run real-time AI evaluation on draft answers"list applications", "show applications"List applications for program"application details", "show application"Get application by reference"approve application"Update status to approved (requires amount + currency)"reject application"Update status to rejected"request revision"Update status to revision_requested"milestone completions", "show milestones"List milestone completions"pending milestones", "unverified milestones"List milestone completions, filter by isVerified: false"create payout", "disburse funds"Create disbursement batch"payout history"Get payout history for grant"total disbursed", "how much paid"Get total disbursed"pending payouts"List pending disbursements"awaiting signatures"List disbursements awaiting Safe signatures"grant agreement", "agreement status"Get grant agreement"sign agreement", "mark agreement signed"Toggle agreement to signed"evaluate application", "AI score"Trigger public AI evaluation"internal evaluation", "admin AI score"Trigger internal AI evaluation"add comment", "leave note"Add application comment"show comments", "list comments"List application comments"program stats", "application statistics"Get program report"program details", "show program"Get program details"community programs", "list programs"List community programs
StatusMeaningAction400Bad paramsShow error, help fix401Invalid API keyTell user to check KARMA_API_KEY or run setup403Insufficient permissionsUser lacks the required role for this program404Not foundCheck reference number or program ID429Rate limited (60/min)Wait and retry500Server errorRetry once, then report
ScenarioResponseMissing required fieldAsk user for itAPI key not setRun setup flowNeed reference number but user gave nameSearch applications by name/emailApproving without amountAsk for approved amount and currencyMultiple programs in communityShow list, ask which oneReviewer already existsShow the 409 error messageEthereum address not lowercaseNormalize to lowercase before sending"Create a program"Full 3-step flow: create in registry → create funding config → configure intake formIntake form has no email fieldReject — form must have at least one email field for trackingProgram limit exceeded (409)Community already has a program — non-staff users are limited to 1 per communityUpdate program without fetching firstAlways fetch current details and merge — PUT replaces metadata