Workspace API
Invite a User
Create a workspace invitation with POST /workspace/invitations.
POST https://api.parcelengineering.com/api/v1/workspace/invitationsCreates an invitation for a single email address and dispatches the invite email. The caller must be an owner or admin (for user-token requests). API key callers are admin-equivalent.
The seat limit counts both current members and all live pending invitations. An invitation that would push the total over the plan limit returns 403 seat_limit_reached.
Invite a user costs 0 credits.
The Workspace API requires the Pro plan. A request from a non-Pro workspace receives 403 forbidden.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address to invite. Must be a valid email. Use .example domains in test environments. |
role | string | No | Role to assign when the invitation is accepted: admin or member. Defaults to member. The owner role is not invitable. |
Errors
| Code | Status | Description |
|---|---|---|
invalid_email | 400 | The email address is not valid. |
forbidden | 403 | The caller is not an owner or admin in this workspace. |
seat_limit_reached | 403 | Accepting this invitation would exceed the plan’s seat limit. The limit counts current members plus all live pending invitations. Remove a member or revoke a pending invitation before sending a new one. |
invite_already_pending | 409 | A live (unexpired) pending invitation already exists for this email. An expired invitation is refreshed and re-sent instead. Revoke the existing live invitation first if you want to change it. |
email_config_missing | 503 | The email sending integration is not configured on this deployment. Contact support. |
Example
curl -X POST https://api.parcelengineering.com/api/v1/workspace/invitations \ -H "Authorization: Bearer pcl_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "email": "new.teammate@example.com", "role": "member" }'const response = await fetch( 'https://api.parcelengineering.com/api/v1/workspace/invitations', { method: 'POST', headers: { 'Authorization': 'Bearer pcl_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: 'new.teammate@example.com', role: 'member', }), });
const { data, metadata } = await response.json();Response
Returns HTTP 201 on success.
{ "data": { "invitation": { "id": "9f8e7d6c-0001-4a3b-8c2d-000000000001", "email": "new.teammate@example.com", "role": "member", "expires_at": "2025-07-13T12:00:00.000Z", "sent": true } }, "metadata": { "credits": 0 }}Response fields
| Field | Type | Description |
|---|---|---|
data.invitation.id | string (UUID) | The invitation row id. Use this to revoke the invitation via Revoke an Invitation. |
data.invitation.email | string | The email address that was invited. |
data.invitation.role | string | The role assigned when the invitation is accepted: admin or member. |
data.invitation.expires_at | string (ISO 8601) | When the invitation link expires. Typically 14 days from creation. |
data.invitation.sent | boolean | true if the invite email was dispatched successfully; false if the record was created but email delivery failed. |
metadata.credits | integer | Always 0. |