Packets API

A packet is a bundle of forms and documents that you send to one or more people to complete as a single, trackable unit. You design a reusable packet template once, then start individual packets from it whenever you need to collect signatures, onboard a new hire, or gather a set of related submissions. The Packets API lets you manage that whole lifecycle programmatically: build and maintain templates, kick off new packets, watch their progress submission by submission, and nudge anyone who has fallen behind.

Packets API

Reach for this API when you want to automate sending bundles of forms (for example, generating an onboarding packet the moment a candidate accepts an offer), sync packet status into your own dashboards, or drive reminders from your own scheduling logic. If you only need a single form rather than a bundle, the Forms and Submissions APIs may be a better fit.

Basics

Every request goes to the base URL https://api.droplet.io, with the paths below appended to it. Authenticate by sending your JWT in the Authorization header on each call:

Authorization: Bearer <token>

Path parameters are shown with a leading colon, like /v1/packets/:id. Replace the whole placeholder (including the colon) with a real value.

All responses share a common envelope. A success looks like this:

{
  "requestId": "req_8f2c1a",
  "success": true,
  "data": { /* ... */ }
}

On failure, success is false and an error object with code and message replaces data:

{
  "requestId": "req_8f2c1a",
  "success": false,
  "error": { "code": "not_found", "message": "Packet not found" }
}

The data shape differs per endpoint and is documented with each one below. Mutating endpoints that act on a list (archive, restore, tags) return a simple { "count": N } telling you how many records were affected. Examples show the fields you will most commonly use; a record may include more, so ignore any you do not recognize.

Packet templates

Templates are the blueprints for your packets. They define which forms and documents are included, who gets assigned to each, the notifications that fire as the packet moves along, and the branding shown in the recipient portal.

List packet templates

GET /v1/packets/templates

Returns the packet templates that match your filters. Use it to populate a template picker or to find a template by name before starting a packet.

Query paramTypeDescription
showstringOne of all, archived, active, voided. Defaults to active templates.
searchstringFree-text search across template names and descriptions.
includestring or arrayComma-separated extra fields to expand, e.g. name,description.
tagKeystringFilter to templates carrying this managed tag key.
tagValuestringFilter to templates whose tagKey has this value.
curl https://api.droplet.io/v1/packets/templates?show=active&search=onboarding \
  -H "Authorization: Bearer <token>"

data is an array of template objects.

{
  "requestId": "req_a1",
  "success": true,
  "data": [
    {
      "id": "tmpl_9k2",
      "name": "New Hire Onboarding",
      "description": "Forms every new employee completes on day one",
      "subject": { "role": "Employee" },
      "forms": [
        {
          "type": "form",
          "formId": "form_w4",
          "name": "W-4 Withholding",
          "assignee": { "type": "role", "name": "Employee" },
          "loginRequired": false,
          "published": true
        }
        // ...
      ],
      "contributors": [{ "role": "HR Manager" }],
      "notifications": [
        {
          "type": "packetReminder",
          "label": "Weekly nudge",
          "notificationTrigger": { "when": { "interval": 3, "unit": "day" } }
        }
      ],
      "created": "2026-01-04T12:00:00Z",
      "modified": "2026-05-18T09:30:00Z",
      "archived": false,
      "status": "active",
      "portalTitle": "Welcome to Droplet",
      "tags": { "department": "people-ops" }
    }
    // ...
  ]
}

Create a packet template

POST /v1/packets/templates

Creates a new template. Only name is required; everything else can be filled in now or via a later update. The forms array lists the forms and documents the packet bundles, each optionally pre-assigned to a role or person.

Body fieldTypeDescription
namestringRequired. The template name.
descriptionstringOptional summary shown to staff.
subjectobjectWho the packet is about, e.g. { "role": "Employee" }, or {} for none.
formsarrayItems with type (form or document), formId, and an optional assignee / assignees (each role or person).
contributorsarrayRoles that can contribute to the packet, e.g. [{ "role": "Manager" }].
notificationsarrayReminder and event notifications (see note below).
portalTitle, portalOrgName, portalDescription, portalLogoPathstringBranding for the recipient portal.

Each notification is one of two shapes. A packetReminder carries a notificationTrigger with a when (and optional repeating) interval and unit (minute, hour, day, week, month). Event notifications (packetAllCompleted, packetAllStarted, packetAnyRejected, packetAssignment) instead carry a recipients array of person or role entries.

curl -X POST https://api.droplet.io/v1/packets/templates \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "New Hire Onboarding",
    "description": "Day-one paperwork",
    "subject": { "role": "Employee" },
    "forms": [
      { "type": "form", "formId": "form_w4", "assignee": { "type": "role", "name": "Employee" } }
    ],
    "notifications": [
      { "type": "packetAllCompleted", "recipients": [{ "type": "role", "name": "HR Manager" }] }
    ]
  }'

data is the created template object, identical in shape to a list item above.

{
  "requestId": "req_a2",
  "success": true,
  "data": { "id": "tmpl_9k2", "name": "New Hire Onboarding", "archived": false /* ... */ }
}

List forms available for templates

GET /v1/packets/templates/forms

Returns the forms and documents you can drop into a template's forms array. Use it to build a form picker when authoring a template.

curl https://api.droplet.io/v1/packets/templates/forms \
  -H "Authorization: Bearer <token>"

data is an array of form references.

{
  "requestId": "req_a3",
  "success": true,
  "data": [
    {
      "type": "form",
      "formId": "form_w4",
      "name": "W-4 Withholding",
      "assignees": [{ "type": "role", "name": "Employee" }]
    }
    // ...
  ]
}

Retrieve a packet template

GET /v1/packets/templates/:packetTemplateId

Returns a single template by ID.

ParamInDescription
packetTemplateIdpathRequired. The template ID.
includequeryComma-separated extra fields to expand, e.g. name,description.
curl https://api.droplet.io/v1/packets/templates/tmpl_9k2 \
  -H "Authorization: Bearer <token>"

data is a single template object, same shape as the create response.

Update a packet template

PUT /v1/packets/templates/:packetTemplateId

Updates an existing template. Send only the fields you want to change; the accepted body matches Create a packet template (all fields optional here, since the template already exists).

curl -X PUT https://api.droplet.io/v1/packets/templates/tmpl_9k2 \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "description": "Updated day-one paperwork", "portalTitle": "Welcome aboard" }'

data is the updated template object.

{
  "requestId": "req_a4",
  "success": true,
  "data": { "id": "tmpl_9k2", "description": "Updated day-one paperwork" /* ... */ }
}

Update tags on packet templates

PUT /v1/packets/templates/tags

Adds or removes managed tags across one or more templates in a single call. Use set to assign key/value pairs and remove to drop keys.

Body fieldTypeDescription
idsarrayRequired. The template IDs to update.
setobjectTag key/value pairs to set on each template.
removearrayTag keys to remove from each template.
curl -X PUT https://api.droplet.io/v1/packets/templates/tags \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["tmpl_9k2", "tmpl_4p1"], "set": { "department": "people-ops" }, "remove": ["legacy"] }'
{ "requestId": "req_a5", "success": true, "data": { "count": 2 } }

Archive packet templates

POST /v1/packets/templates/archive

Archives one or more templates so they no longer appear in active lists. Archiving does not affect packets already started from a template.

Body fieldTypeDescription
packetTemplateIdsarrayRequired. The template IDs to archive.
curl -X POST https://api.droplet.io/v1/packets/templates/archive \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "packetTemplateIds": ["tmpl_9k2"] }'
{ "requestId": "req_a6", "success": true, "data": { "count": 1 } }

Restore packet templates

POST /v1/packets/templates/restore

Brings previously archived templates back into active use.

Body fieldTypeDescription
packetTemplateIdsarrayRequired. The archived template IDs to restore.
curl -X POST https://api.droplet.io/v1/packets/templates/restore \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "packetTemplateIds": ["tmpl_9k2"] }'
{ "requestId": "req_a7", "success": true, "data": { "count": 1 } }

Upload a template asset

POST /v1/packets/templates/asset

Uploads a file (such as a portal logo) for a template. Send the file contents as a string along with its MIME type and extension; the response gives you back the stored path, which you can then save to a write field like portalLogoPath. On reads, the rendered logo comes back as portalLogoUrl.

Body fieldTypeDescription
packetTemplateIdstringRequired. The template the asset belongs to.
filestringRequired. The file contents (for example, base64-encoded).
fileTypeobjectRequired. { "mime": "image/png", "ext": "png" }.
curl -X POST https://api.droplet.io/v1/packets/templates/asset \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "packetTemplateId": "tmpl_9k2",
    "file": "iVBORw0KGgoAAAANSUhEUgAA...",
    "fileType": { "mime": "image/png", "ext": "png" }
  }'
{ "requestId": "req_a8", "success": true, "data": { "path": "assets/tmpl_9k2/logo.png" } }

Packets

Packets are live instances started from a template. Each one tracks a subject, the people assigned to its forms, and a set of submissions that progress from draft to completed.

List packet IDs

GET /v1/packets/ids

Returns the IDs of packets matching your filters, plus a total count. This is the paginated entry point for browsing packets: fetch the matching IDs here, then hydrate the ones you need with Retrieve packets by ID.

Query paramTypeDescription
pageintegerZero-based page number.
packetSubjectstringFilter by the packet's subject.
packetTemplateIdstringOnly packets started from this template.
formIdstringOnly packets that include this form.
employeeIdsarrayFilter to packets for these employees.
statusstringFilter by packet status.
showstringOne of all, archived, active, voided.
searchstringFree-text search.
created, modifiedstringDate filters.
tagKey, tagValuestringFilter by managed tag.
curl "https://api.droplet.io/v1/packets/ids?packetTemplateId=tmpl_9k2&status=pending&page=0" \
  -H "Authorization: Bearer <token>"
{
  "requestId": "req_b1",
  "success": true,
  "data": { "count": 42, "ids": ["pkt_001", "pkt_002", "pkt_003"] }
}

Retrieve packets by ID

POST /v1/packets/entities

Returns full packet records for a list of IDs. Pass the IDs in the body; this is the companion to List packet IDs for batch hydration.

FieldInDescription
idsbodyRequired. Array of packet IDs to fetch.
includequeryComma-separated extra fields to expand, e.g. subject,initiatedBy.
curl -X POST "https://api.droplet.io/v1/packets/entities?include=subject,initiatedBy" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["pkt_001", "pkt_002"] }'

data is an array of packet objects (the same shape returned by Retrieve a packet).

{
  "requestId": "req_b2",
  "success": true,
  "data": [
    {
      "id": "pkt_001",
      "name": "Onboarding - Jordan Lee",
      "status": "pending",
      "subject": { "type": "contributor", "name": "Jordan Lee", "email": "jordan@example.com" },
      "packetTemplateId": "tmpl_9k2",
      "initiatedBy": { "name": "Sam Rivera", "email": "sam@droplet.io" },
      "packetSubmissions": [ /* ... */ ]
    }
    // ...
  ]
}

Retrieve a packet

GET /v1/packets/:id

Returns a single packet, including its submissions, assignees, status, and portal details.

ParamInDescription
idpathRequired. The packet ID.
includequeryComma-separated extra fields to expand, e.g. subject,initiatedBy.
showqueryOne of all, archived, active, voided.
curl https://api.droplet.io/v1/packets/pkt_001 \
  -H "Authorization: Bearer <token>"
{
  "requestId": "req_b3",
  "success": true,
  "data": {
    "id": "pkt_001",
    "created": "2026-06-01T08:00:00Z",
    "name": "Onboarding - Jordan Lee",
    "organizationName": "Acme Co",
    "packetPortalUrl": "https://portal.droplet.io/p/pkt_001",
    "subject": { "type": "contributor", "name": "Jordan Lee", "email": "jordan@example.com" },
    "packetTemplateId": "tmpl_9k2",
    "status": "pending",
    "initiatedBy": { "name": "Sam Rivera", "email": "sam@droplet.io" },
    "packetSubmissions": [
      {
        "id": 5501,
        "type": "submissions",
        "formId": "form_w4",
        "formName": "W-4 Withholding",
        "assignedTo": [
          { "name": "Jordan Lee", "email": "jordan@example.com",
            "emailStatus": { "status": "delivered" } }
        ],
        "status": "pending",
        "progress": { "stepLabel": "In progress", "percent": 40 },
        "submissionUrl": "https://app.droplet.io/s/5501"
      }
      // ...
    ]
  }
}

A packet's status is one of draft, pending, completed, or rejected. The subject can be a contributor (with name and email), a label, or an empty object when none is set. Each entry in packetSubmissions has a type of submissions (a form) or documentSubmissions (a document), so branch on both values.

Retrieve packet portal data

GET /v1/packets/:id/portal

Returns the same packet record shaped for portal access, the read-only view a recipient sees. Use it to render or mirror the recipient-facing experience.

ParamInDescription
idpathRequired. The packet ID.
curl https://api.droplet.io/v1/packets/pkt_001/portal \
  -H "Authorization: Bearer <token>"

data is a packet object in the same shape as Retrieve a packet, including packetSubmissions and portal branding fields.

List submissions for packets

POST /v1/packets/submissions

Returns every submission for one or more packets, complete with per-submission progress and permissions. Pass packet IDs in the body; the response is keyed by packet ID so you can fan out a single call across many packets.

Body fieldTypeDescription
idsarrayRequired. Packet IDs whose submissions you want.
curl -X POST https://api.droplet.io/v1/packets/submissions \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["pkt_001", "pkt_002"] }'

data is an object mapping each packet ID to its array of submissions.

{
  "requestId": "req_b4",
  "success": true,
  "data": {
    "pkt_001": [
      {
        "id": 5501,
        "type": "submissions",
        "formId": "form_w4",
        "formName": "W-4 Withholding",
        "status": "completed",
        "completed": "2026-06-03T14:22:00Z",
        "progress": { "stepLabel": "Done", "percent": 100 }
      }
      // ...
    ]
    // ...
  }
}

Create a packet

POST /v1/packets

Starts a new packet from a template and sends it on its way. You name the subject, point at the template, and supply at least one submission describing each form or document and who it goes to.

Body fieldTypeDescription
subjectobjectRequired. Who the packet is about, in one of these shapes. A person or contributor: { "type": "person", "name": "...", "email": "..." }. A role: { "role": "..." }. A label: { "type": "label", "label": "..." }.
packetTemplateIdstringRequired. The template to start from.
submissionsarrayRequired, at least one item. See the variants below.
initiatedByobjectOptional. The name and email of the person starting the packet.
contributorsobjectOptional contributors keyed by role.

Each submissions item is one of three shapes:

  • A form submission: { "type": "form", "formId": "...", "assignedTo": { "name": "...", "email": "..." }, "data": {} }. The data object can prefill answers.
  • A document submission: { "type": "document", "formId": "...", "assignees": [{ "type": "person", "name": "...", "email": "..." }] }.
  • A reference to an existing submission by numeric id: { "id": 5501 }.
curl -X POST https://api.droplet.io/v1/packets \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": { "type": "person", "name": "Jordan Lee", "email": "jordan@example.com" },
    "packetTemplateId": "tmpl_9k2",
    "submissions": [
      { "type": "form", "formId": "form_w4",
        "assignedTo": { "name": "Jordan Lee", "email": "jordan@example.com" } }
    ],
    "initiatedBy": { "name": "Sam Rivera", "email": "sam@droplet.io" }
  }'

data is the newly created packet object, same shape as Retrieve a packet.

{
  "requestId": "req_b5",
  "success": true,
  "data": { "id": "pkt_001", "status": "pending", "packetPortalUrl": "https://portal.droplet.io/p/pkt_001" /* ... */ }
}

Update tags on packets

PUT /v1/packets/tags

Adds or removes managed tags across one or more packets, mirroring the template tag endpoint.

Body fieldTypeDescription
idsarrayRequired. The packet IDs to update.
setobjectTag key/value pairs to set.
removearrayTag keys to remove.
curl -X PUT https://api.droplet.io/v1/packets/tags \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["pkt_001"], "set": { "cohort": "2026-Q2" } }'
{ "requestId": "req_b6", "success": true, "data": { "count": 1 } }

Archive packets

POST /v1/packets/archive

Archives one or more packets, removing them from active views.

Body fieldTypeDescription
idsarrayRequired. The packet IDs to archive.
curl -X POST https://api.droplet.io/v1/packets/archive \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["pkt_001"] }'
{ "requestId": "req_b7", "success": true, "data": { "count": 1 } }

Restore packets

POST /v1/packets/restore

Restores previously archived packets back to active status.

Body fieldTypeDescription
idsarrayRequired. The archived packet IDs to restore.
curl -X POST https://api.droplet.io/v1/packets/restore \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["pkt_001"] }'
{ "requestId": "req_b8", "success": true, "data": { "count": 1 } }

Send packet reminders

POST /v1/packets/:id/remind

Emails a reminder to every assignee in this packet who still has an incomplete submission. Optionally override the email's subject and body; omit emailTemplate to use the default reminder copy. The response tells you how many reminders went out.

FieldInDescription
idpathRequired. The packet ID.
emailTemplatebodyOptional. Object with subject and body to customize the reminder.
curl -X POST https://api.droplet.io/v1/packets/pkt_001/remind \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "emailTemplate": { "subject": "A quick nudge", "body": "Please wrap up your onboarding forms." } }'
{ "requestId": "req_b9", "success": true, "data": { "count": 2 } }
Last reviewed by Nick Duell and published on June 22, 2026 3PM ET