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.

Keep your keys secret. Never expose them in client-side code or public repositories. Use environment variables or a secrets manager in production.

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
curl https://api.drop.top/v1/collections \
  -H "Authorization: Bearer dt_live_sk_xxxxxxxxxxxx" \
  -H "Content-Type: application/json"
Node.js
const DropTop = require('@droptop/node');

const client = new DropTop({
  apiKey: process.env.DROPTOP_API_KEY
});
Python
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.

Growth
120
requests / minute
Enterprise
600
requests / minute
Global
custom limit (contact us)

Rate limit headers

Every API response includes rate limit info in the response headers.

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.

StatusCodeDescription
400validation_errorRequest body failed schema validation. Check the details array for field-level errors.
401unauthorizedMissing or invalid API key. Verify your Authorization header.
403forbiddenThe API key does not have permission to access this resource.
404not_foundThe requested resource does not exist.
409duplicate_submissionA submission for this entity and period already exists in this collection.
422file_unreadableThe file at file_url could not be fetched or parsed.
429rate_limit_exceededToo many requests. Use Retry-After header to back off.
500internal_errorSomething went wrong on our end. We track these automatically.

Error response shape

400 Error
{
  "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.

Recommended: Use webhooks instead of polling. They're significantly faster and reduce API usage — especially for high-volume file collections.

Supported events

submission.received
Fired as soon as a file is received (via any channel). Processing hasn't started yet.
submission.validated
File passed all validation rules. Includes full column match report.
submission.failed
Validation failed. Includes row-level errors and suggested fixes.
collection.closed
All entities in a collection have submitted and passed validation.
entity.overdue
An entity missed its deadline. Triggered per entity individually.

Verifying signatures

Every webhook includes a Droptop-Signature header — a HMAC-SHA256 hex digest of the raw request body, signed with your webhook secret.

Node.js
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.

TypeScript / Node.js
@droptop/node · v1.4.2
Python
droptop · v1.3.9
Java
com.droptop · v1.1.0
Install
# 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

GET/v1/collections

Returns a paginated list of all collections in your workspace. Collections are sorted by creation date, most recent first.

Query parameters

ParameterTypeDescription
limitoptionalintegerNumber of results per page. Default: 20. Max: 100.
afteroptionalstringCursor for pagination. Pass the next_cursor from the previous response.
statusoptionalstringFilter by status: open, closed, or archived.
cURL
curl "https://api.drop.top/v1/collections?status=open&limit=20" \
  -H "Authorization: Bearer dt_live_sk_xxxx"
200 Response
{
  "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

POST/v1/collections

Creates a new file collection. Define your template schema, validation rules, and deadline configuration at creation time.

Request body

ParameterTypeDescription
namerequiredstringHuman-readable name for this collection.
template_idrequiredstringID of the validation template to use. Templates define required columns and data types.
deadlinerequiredstringISO 8601 datetime. Entities submitting after this will be flagged as overdue.
reminder_scheduleoptionalobjectConfigure automated reminder emails. See reminder schema below.
metadataoptionalobjectArbitrary key-value pairs for your own use.
Request body
{
  "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
  }
}
201 Created
{
  "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

GET/v1/collections/{collection_id}

Retrieves a single collection by ID, including its full submission status breakdown and validation summary.

cURL
curl https://api.drop.top/v1/collections/col_01hzxkn23m \
  -H "Authorization: Bearer dt_live_sk_xxxx"
200 Response
{
  "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

POST/v1/collections/{collection_id}/submissions

Submit 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).

File size: Files under 25 MB are processed synchronously. Larger files are queued and results delivered via submission.validated or submission.failed webhooks.

Request body

ParameterTypeDescription
entity_idrequiredstringThe entity submitting this file.
file_urlrequiredstringPublicly accessible URL to the file. Supports XLSX, XLS, CSV. Max 100 MB.
metadataoptionalobjectArbitrary key-value pairs. Useful for period, submitter info, etc.
resubmitoptionalbooleanSet to true to overwrite an existing submission. Default: false.
cURL
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"
    }
  }'
Node.js
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"
  }
});
Python
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"
  }
)
200 Response
{
  "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

GET/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
curl https://api.drop.top/v1/submissions/sub_01j2mxktn3 \
  -H "Authorization: Bearer dt_live_sk_xxxx"

List Submissions

GET/v1/collections/{collection_id}/submissions

Returns all submissions for a collection. Filter by entity, status, or date range. Paginated with cursor-based pagination.

ParameterTypeDescription
entity_idoptionalstringFilter to a specific entity's submissions.
statusoptionalstringpending, validated, failed
limitoptionalintegerDefault: 20. Max: 100.
afteroptionalstringPagination cursor from previous response.

List Entities

GET/v1/entities

Returns all entities in your workspace. Entities represent subsidiaries, business units, or any data-submitting party.

cURL
curl https://api.drop.top/v1/entities \
  -H "Authorization: Bearer dt_live_sk_xxxx"
200 Response
{
  "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

POST/v1/entities

Creates a new entity. Each entity can have unique upload credentials, a dedicated submission email address, and custom validation templates.

ParameterTypeDescription
namerequiredstringHuman-readable name for this entity (e.g. subsidiary or BU name).
emailrequiredstringPrimary contact email. Used for automatic reminders and notifications.
countryoptionalstringISO 3166-1 alpha-2 country code.
tagsoptionalarrayArray of strings for grouping/filtering entities.
metadataoptionalobjectArbitrary key-value store for your own use.

Get Entity

GET/v1/entities/{entity_id}

Retrieves a single entity including its upload credentials and submission history summary.

Get Validation Result

GET/v1/submissions/{submission_id}/validation

Returns the full validation report for a submission, including row-level errors, column mapping decisions made by the AI, and all normalisation actions taken.

cURL
curl https://api.drop.top/v1/submissions/sub_01j2mxktn3/validation \
  -H "Authorization: Bearer dt_live_sk_xxxx"
200 Response
{
  "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

POST/v1/submissions/{submission_id}/validate

Triggers a fresh validation run on an existing submission. Useful when a validation template is updated and you want to re-check already submitted files.

Note: Re-running validation will overwrite the existing validation result. The previous result is archived and accessible via the audit log.
cURL
curl -X POST https://api.drop.top/v1/submissions/sub_01j2mxktn3/validate \
  -H "Authorization: Bearer dt_live_sk_xxxx"
202 Accepted
{
  "submission_id": "sub_01j2mxktn3",
  "status": "pending",
  "message": "Validation queued. Results will be delivered via webhook."
}