Authentication
All Drop.Top API requests are authenticated using Bearer tokens. API keys are scoped to your workspace and generated in Settings → API Keys. Two key types exist: live keys for production and test keys for development.
API key format
Keys are prefixed with dt_live_sk_ for production or dt_test_sk_ for sandbox environments. All keys are 32 characters after the prefix.
curl https://api.drop.top/v1/collections \ -H "Authorization: Bearer dt_live_sk_xxxxxxxxxxxx" \ -H "Content-Type: application/json"
const DropTop = require('@droptop/node'); const client = new DropTop({ apiKey: process.env.DROPTOP_API_KEY });
import droptop import os client = droptop.Client( api_key=os.environ["DROPTOP_API_KEY"] )
Base URL
All API requests are made to: https://api.drop.top/v1
Rate Limits
API calls are rate limited per API key. Limits apply per minute and per day. When a limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header.
Rate limit headers
Every API response includes rate limit info in the response headers.
X-RateLimit-Limit: 600 X-RateLimit-Remaining: 594 X-RateLimit-Reset: 1712345678 Retry-After: 32
Errors
Drop.Top uses standard HTTP status codes and returns a consistent JSON error object for all failures. Always check the code field for machine-readable error handling.
| Status | Code | Description |
|---|---|---|
| 400 | validation_error | Request body failed schema validation. Check the details array for field-level errors. |
| 401 | unauthorized | Missing or invalid API key. Verify your Authorization header. |
| 403 | forbidden | The API key does not have permission to access this resource. |
| 404 | not_found | The requested resource does not exist. |
| 409 | duplicate_submission | A submission for this entity and period already exists in this collection. |
| 422 | file_unreadable | The file at file_url could not be fetched or parsed. |
| 429 | rate_limit_exceeded | Too many requests. Use Retry-After header to back off. |
| 500 | internal_error | Something went wrong on our end. We track these automatically. |
Error response shape
{
"error": {
"code": "validation_error",
"message": "Request body is invalid.",
"details": [
{
"field": "entity_id",
"message": "entity_id is required"
}
],
"request_id": "req_01j3xmkz8p"
}
}Webhooks
Webhooks deliver real-time notifications to your server when key events occur in Drop.Top. Configure endpoints per collection in Settings → Webhooks. We sign every request with HMAC-SHA256.
Supported events
Verifying signatures
Every webhook includes a Droptop-Signature header — a HMAC-SHA256 hex digest of the raw request body, signed with your webhook secret.
const crypto = require('crypto'); function verifyWebhook(rawBody, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) ); }
SDKs & Libraries
Official Drop.Top SDKs for the most popular languages. All SDKs are generated from our OpenAPI spec and kept in sync with every API release.
# npm npm install @droptop/node # pip pip install droptop # maven <dependency> <groupId>com.droptop</groupId> <artifactId>droptop-java</artifactId> <version>1.1.0</version> </dependency>
List Collections
/v1/collectionsReturns a paginated list of all collections in your workspace. Collections are sorted by creation date, most recent first.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| limitoptional | integer | Number of results per page. Default: 20. Max: 100. |
| afteroptional | string | Cursor for pagination. Pass the next_cursor from the previous response. |
| statusoptional | string | Filter by status: open, closed, or archived. |
curl "https://api.drop.top/v1/collections?status=open&limit=20" \ -H "Authorization: Bearer dt_live_sk_xxxx"
{
"data": [
{
"id": "col_01hzxkn23m",
"name": "Q1 FY2026 Reporting",
"status": "open",
"entity_count": 148,
"submitted_count": 97,
"deadline": "2026-02-28T23:59:00Z",
"created_at": "2025-12-01T08:00:00Z"
}
],
"next_cursor": "col_01hzabc99k",
"has_more": true
}Create Collection
/v1/collectionsCreates a new file collection. Define your template schema, validation rules, and deadline configuration at creation time.
Request body
| Parameter | Type | Description |
|---|---|---|
| namerequired | string | Human-readable name for this collection. |
| template_idrequired | string | ID of the validation template to use. Templates define required columns and data types. |
| deadlinerequired | string | ISO 8601 datetime. Entities submitting after this will be flagged as overdue. |
| reminder_scheduleoptional | object | Configure automated reminder emails. See reminder schema below. |
| metadataoptional | object | Arbitrary key-value pairs for your own use. |
{
"name": "Q1 FY2026 Reporting",
"template_id": "tpl_01hzxkn88k",
"deadline": "2026-02-28T23:59:00Z",
"reminder_schedule": {
"intervals_days": [7, 3, 1],
"escalate_after_days": 2
}
}{
"id": "col_01j2mxktn3",
"name": "Q1 FY2026 Reporting",
"status": "open",
"entity_count": 0,
"submitted_count": 0,
"deadline": "2026-02-28T23:59:00Z",
"created_at": "2026-01-10T09:00:00Z"
}Get Collection
/v1/collections/{collection_id}Retrieves a single collection by ID, including its full submission status breakdown and validation summary.
curl https://api.drop.top/v1/collections/col_01hzxkn23m \ -H "Authorization: Bearer dt_live_sk_xxxx"
{
"id": "col_01hzxkn23m",
"name": "Q1 FY2026 Reporting",
"status": "open",
"entity_count": 148,
"submitted_count": 97,
"validated_count": 89,
"overdue_count": 23,
"deadline": "2026-02-28T23:59:00Z"
}Submit File
/v1/collections/{collection_id}/submissionsSubmit a file for a specific entity within a collection. Drop.Top will fetch the file from the provided URL, run all validation rules, and return a result synchronously (or deliver it via webhook for large files).
submission.validated or submission.failed webhooks.Request body
| Parameter | Type | Description |
|---|---|---|
| entity_idrequired | string | The entity submitting this file. |
| file_urlrequired | string | Publicly accessible URL to the file. Supports XLSX, XLS, CSV. Max 100 MB. |
| metadataoptional | object | Arbitrary key-value pairs. Useful for period, submitter info, etc. |
| resubmitoptional | boolean | Set to true to overwrite an existing submission. Default: false. |
curl -X POST https://api.drop.top/v1/collections/col_01hzxkn23m/submissions \ -H "Authorization: Bearer dt_live_sk_xxxx" \ -H "Content-Type: application/json" \ -d '{ "entity_id": "ent_01hzxkn88k", "file_url": "https://yourhost.com/q1_emea.xlsx", "metadata": { "submitted_by": "[email protected]", "period": "2026-Q1" } }'
const result = await client.submissions.create({ collection_id: "col_01hzxkn23m", entity_id: "ent_01hzxkn88k", file_url: "https://yourhost.com/q1_emea.xlsx", metadata: { submitted_by: "[email protected]", period: "2026-Q1" } });
result = client.submissions.create( collection_id="col_01hzxkn23m", entity_id="ent_01hzxkn88k", file_url="https://yourhost.com/q1_emea.xlsx", metadata={ "submitted_by": "[email protected]", "period": "2026-Q1" } )
{
"submission_id": "sub_01j2mxktn3",
"status": "validated",
"columns_matched": 14,
"columns_total": 14,
"row_count": 1248,
"errors": [],
"warnings": [
{
"row": 42,
"column": "ReportDate",
"message": "Date format DD/MM detected, normalised to MM/DD."
}
],
"created_at": "2026-01-15T11:23:00Z"
}Get Submission
/v1/submissions/{submission_id}Retrieve a submission by ID. Use this to poll for the result of an async (large file) submission, or to retrieve the full validation report at any time.
curl https://api.drop.top/v1/submissions/sub_01j2mxktn3 \ -H "Authorization: Bearer dt_live_sk_xxxx"
List Submissions
/v1/collections/{collection_id}/submissionsReturns all submissions for a collection. Filter by entity, status, or date range. Paginated with cursor-based pagination.
| Parameter | Type | Description |
|---|---|---|
| entity_idoptional | string | Filter to a specific entity's submissions. |
| statusoptional | string | pending, validated, failed |
| limitoptional | integer | Default: 20. Max: 100. |
| afteroptional | string | Pagination cursor from previous response. |
List Entities
/v1/entitiesReturns all entities in your workspace. Entities represent subsidiaries, business units, or any data-submitting party.
curl https://api.drop.top/v1/entities \ -H "Authorization: Bearer dt_live_sk_xxxx"
{
"data": [
{
"id": "ent_01hzxkn88k",
"name": "EMEA Holdings GmbH",
"email": "[email protected]",
"country": "DE",
"tags": ["emea", "tier-1"],
"created_at": "2025-10-01T00:00:00Z"
}
],
"next_cursor": null,
"has_more": false
}Create Entity
/v1/entitiesCreates a new entity. Each entity can have unique upload credentials, a dedicated submission email address, and custom validation templates.
| Parameter | Type | Description |
|---|---|---|
| namerequired | string | Human-readable name for this entity (e.g. subsidiary or BU name). |
| emailrequired | string | Primary contact email. Used for automatic reminders and notifications. |
| countryoptional | string | ISO 3166-1 alpha-2 country code. |
| tagsoptional | array | Array of strings for grouping/filtering entities. |
| metadataoptional | object | Arbitrary key-value store for your own use. |
Get Entity
/v1/entities/{entity_id}Retrieves a single entity including its upload credentials and submission history summary.
Get Validation Result
/v1/submissions/{submission_id}/validationReturns the full validation report for a submission, including row-level errors, column mapping decisions made by the AI, and all normalisation actions taken.
curl https://api.drop.top/v1/submissions/sub_01j2mxktn3/validation \ -H "Authorization: Bearer dt_live_sk_xxxx"
{
"submission_id": "sub_01j2mxktn3",
"status": "validated",
"columns_matched": 14,
"errors": [],
"warnings": [
{
"row": 42,
"column": "ReportDate",
"message": "Date format normalised: DD/MM → MM/DD"
}
],
"column_mapping": [
{
"source": "Rev_EUR_Local",
"target": "Revenue_EUR",
"confidence": 0.97,
"method": "ai_match"
}
]
}Re-run Validation
/v1/submissions/{submission_id}/validateTriggers a fresh validation run on an existing submission. Useful when a validation template is updated and you want to re-check already submitted files.
curl -X POST https://api.drop.top/v1/submissions/sub_01j2mxktn3/validate \ -H "Authorization: Bearer dt_live_sk_xxxx"
{
"submission_id": "sub_01j2mxktn3",
"status": "pending",
"message": "Validation queued. Results will be delivered via webhook."
}