Create, retrieve, update, and list form submissions programmatically using the Grader.io REST API.
The Submissions API allows you to manage form submissions and lead data programmatically. Use it to integrate Grader.io with your existing systems, build custom dashboards, or automate lead processing workflows.
All API requests require authentication using your API key:
curl -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ https://api.grader.io/v1/submissions
Get your API key from Dashboard → Settings → API Keys.
| Method | Endpoint | Description |
|---|---|---|
| POST | | Create new submission |
| GET | | List submissions with filters |
| GET | | Get specific submission |
| PUT | | Update submission data |
| DELETE | | Delete submission |
| POST | | Re-evaluate submission |
Submit form data for scoring and processing.
POST /v1/submissions Content-Type: application/json Authorization: Bearer YOUR_API_KEY { "graderId": "grader_abc123", "source": "website_form", "formData": { "email": "john.doe@acme.com", "firstName": "John", "lastName": "Doe", "company": "Acme Corporation", "jobTitle": "VP Marketing", "phone": "+1-555-0123", "website": "https://acme.com", "message": "Interested in your enterprise solution", "customField1": "High Priority", "customField2": "Referral from partner" }, "metadata": { "ip": "192.168.1.1", "userAgent": "Mozilla/5.0...", "referrer": "https://google.com", "campaign": "fall-2023-enterprise" } }
{ "id": "sub_xyz789", "graderId": "grader_abc123", "source": "website_form", "status": "scored", "score": 87, "grade": "hot", "formData": { "email": "john.doe@acme.com", "firstName": "John", "lastName": "Doe", "company": "Acme Corporation", "jobTitle": "VP Marketing", "phone": "+1-555-0123", "website": "https://acme.com", "message": "Interested in your enterprise solution", "customField1": "High Priority", "customField2": "Referral from partner" }, "routing": { "assignedTo": "rep_sarah_johnson", "team": "enterprise_sales", "territory": "west_coast" }, "createdAt": "2023-10-15T14:30:00Z", "updatedAt": "2023-10-15T14:30:02Z" }
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Grader to process submission |
| string | No | Source identifier (default: "api") |
| object | Yes | Form field data |
| object | No | Additional context data |
Retrieve submissions with filtering and pagination.
GET /v1/submissions?grader=grader_abc123&score_min=80&limit=50&page=1 Authorization: Bearer YOUR_API_KEY
| Parameter | Type | Description | Example |
|---|---|---|---|
| string | Filter by grader ID | |
| number | Minimum score (0-100) | |
| number | Maximum score (0-100) | |
| string | Filter by grade | , , |
| string | Filter by source | |
| string | Start date (ISO 8601) | |
| string | End date (ISO 8601) | |
| string | Filter by email address | |
| string | Filter by company name | |
| string | Filter by assigned rep | |
| string | Filter by status | , , |
| number | Results per page (max 100) | |
| number | Page number | |
| string | Sort field | , , |
| string | Sort direction | , |
{ "data": [ { "id": "sub_xyz789", "graderId": "grader_abc123", "score": 87, "grade": "hot", "formData": { "email": "john.doe@acme.com", "company": "Acme Corporation", "jobTitle": "VP Marketing" }, "routing": { "assignedTo": "rep_sarah_johnson" }, "createdAt": "2023-10-15T14:30:00Z" } ], "pagination": { "page": 1, "limit": 50, "total": 847, "pages": 17, "hasNext": true, "hasPrevious": false }, "filters": { "grader": "grader_abc123", "score_min": 80 } }
Retrieve detailed information about a specific submission.
GET /v1/submissions/sub_xyz789 Authorization: Bearer YOUR_API_KEY
{ "id": "sub_xyz789", "graderId": "grader_abc123", "source": "website_form", "status": "scored", "score": 87, "grade": "hot", "formData": { "email": "john.doe@acme.com", "firstName": "John", "lastName": "Doe", "company": "Acme Corporation", "jobTitle": "VP Marketing", "phone": "+1-555-0123", "website": "https://acme.com", "message": "Interested in your enterprise solution" }, "scoreBreakdown": { "emailDomain": 25, "jobTitle": 20, "companySize": 15, "industry": 12, "formCompletion": 10, "geography": 5 }, "routing": { "assignedTo": "rep_sarah_johnson", "team": "enterprise_sales", "territory": "west_coast", "assignedAt": "2023-10-15T14:30:03Z" }, "metadata": { "ip": "192.168.1.1", "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...", "referrer": "https://google.com/search?q=lead+scoring", "campaign": "fall-2023-enterprise" }, "history": [ { "event": "created", "timestamp": "2023-10-15T14:30:00Z", "user": "api" }, { "event": "scored", "timestamp": "2023-10-15T14:30:02Z", "score": 87, "grader": "grader_abc123" }, { "event": "routed", "timestamp": "2023-10-15T14:30:03Z", "assignedTo": "rep_sarah_johnson" } ], "createdAt": "2023-10-15T14:30:00Z", "updatedAt": "2023-10-15T14:35:00Z" }
Modify submission data and optionally trigger re-scoring.
PUT /v1/submissions/sub_xyz789 Content-Type: application/json Authorization: Bearer YOUR_API_KEY { "formData": { "email": "john.doe@acme.com", "firstName": "John", "lastName": "Doe", "company": "Acme Corporation", "jobTitle": "Senior VP Marketing", "phone": "+1-555-0123", "website": "https://acme.com", "message": "Interested in your enterprise solution for Q1 rollout", "customField1": "Budget Approved", "customField2": "Decision Maker Confirmed" }, "rescore": true }
{ "id": "sub_xyz789", "status": "scored", "score": 92, "grade": "hot", "formData": { "email": "john.doe@acme.com", "firstName": "John", "lastName": "Doe", "company": "Acme Corporation", "jobTitle": "Senior VP Marketing", "phone": "+1-555-0123", "website": "https://acme.com", "message": "Interested in your enterprise solution for Q1 rollout", "customField1": "Budget Approved", "customField2": "Decision Maker Confirmed" }, "updatedAt": "2023-10-15T15:45:00Z" }
Trigger re-evaluation of a submission with current grader criteria.
POST /v1/submissions/sub_xyz789/rescore Authorization: Bearer YOUR_API_KEY
{ "id": "sub_xyz789", "status": "scored", "previousScore": 87, "newScore": 92, "scoreChange": 5, "previousGrade": "hot", "newGrade": "hot", "rescoreDate": "2023-10-15T16:00:00Z" }
Remove a submission and all associated data.
DELETE /v1/submissions/sub_xyz789 Authorization: Bearer YOUR_API_KEY
{ "deleted": true, "id": "sub_xyz789", "deletedAt": "2023-10-15T16:15:00Z" }
{ "error": "validation_error", "message": "Invalid request data", "details": [ { "field": "formData.email", "error": "Invalid email format" }, { "field": "graderId", "error": "Grader not found" } ] }
{ "error": "unauthorized", "message": "Invalid API key" }
{ "error": "not_found", "message": "Submission not found" }
{ "error": "rate_limit_exceeded", "message": "Rate limit exceeded", "retryAfter": 60 }
API requests are rate-limited by plan:
| Plan | Requests/minute | Burst limit |
|---|---|---|
| Starter | 60 | 100 |
| Pro | 300 | 500 |
| Elite | 1,200 | 2,000 |
| Enterprise | Custom | Custom |
Rate limit headers are included in all responses:
X-RateLimit-Limit: 300 X-RateLimit-Remaining: 299 X-RateLimit-Reset: 1634567890
const GraderIO = require('@graderio/sdk'); const client = new GraderIO({ apiKey: process.env.GRADER_API_KEY }); // Create submission const submission = await client.submissions.create({ graderId: 'grader_abc123', formData: { email: 'john.doe@acme.com', company: 'Acme Corporation' } }); console.log(`Submission scored: ${submission.score}`);
import graderio client = graderio.Client(api_key=os.environ['GRADER_API_KEY']) # List high-scoring submissions submissions = client.submissions.list( score_min=80, limit=25 ) for submission in submissions: print(f"{submission.email}: {submission.score}")
use GraderIO\Client; $client = new Client(['api_key' => $_ENV['GRADER_API_KEY']]); // Get submission details $submission = $client->submissions->get('sub_xyz789'); echo "Score: " . $submission->score . "\n"; echo "Grade: " . $submission->grade . "\n";
Combine the Submissions API with webhooks for powerful workflows:
// Webhook handler that enriches data via API app.post('/grader-webhook', async (req, res) => { const { event, data } = req.body; if (event === 'submission.scored' && data.submission.score >= 90) { // Fetch full details for high-value leads const fullSubmission = await client.submissions.get(data.submission.id); // Enrich with additional data await client.submissions.update(fullSubmission.id, { formData: { ...fullSubmission.formData, priority: 'urgent', followUpDate: new Date(Date.now() + 24*60*60*1000).toISOString() } }); // Notify sales team await notifyHighValueLead(fullSubmission); } res.json({ received: true }); });
Process multiple submissions efficiently:
// Bad: Individual API calls for (const lead of leads) { await client.submissions.create(lead); } // Good: Batch processing const batch = leads.slice(0, 100); // Process in chunks const promises = batch.map(lead => client.submissions.create(lead)); const results = await Promise.all(promises);
Implement robust error handling:
async function createSubmissionWithRetry(data, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await client.submissions.create(data); } catch (error) { if (error.status === 429) { // Rate limited - wait and retry await new Promise(resolve => setTimeout(resolve, error.retryAfter * 1000)); continue; } else if (error.status >= 500) { // Server error - retry with backoff await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000)); continue; } else { // Client error - don't retry throw error; } } } throw new Error('Max retries exceeded'); }
Cache frequently accessed data:
const NodeCache = require('node-cache'); const cache = new NodeCache({ stdTTL: 300 }); // 5 minute cache async function getSubmission(id) { const cacheKey = `submission_${id}`; let submission = cache.get(cacheKey); if (!submission) { submission = await client.submissions.get(id); cache.set(cacheKey, submission); } return submission; }