Skip to content

Instantly share code, notes, and snippets.

@vyasgiridhar
Created February 19, 2026 09:08
Show Gist options
  • Select an option

  • Save vyasgiridhar/f70b74c85a015c4f2b8a101cb3c327eb to your computer and use it in GitHub Desktop.

Select an option

Save vyasgiridhar/f70b74c85a015c4f2b8a101cb3c327eb to your computer and use it in GitHub Desktop.
Counterparty Feature — Frontend Integration Guide
# Counterparty Feature — Frontend Integration Guide
## New Role: `COUNTERPARTY`
Counterparties are external parties in contract workflows (e.g., the other side of an agreement). They're now real users with accounts, not magic links.
---
## New Endpoints
### `POST /v1/workflows/{workflow_id}/participants/approve`
**Auth:** JWT + `X-Org-Id`
**Body:** none
**Response:**
```json
{
"approved": true,
"all_parties_ready": false,
"workflow_status": "FINALIZED"
}
```
When all contract principals approve AND `signed_draft_id` is set, workflow auto-transitions to `READY_TO_SIGN`.
---
## Modified Endpoints
### `POST /v1/workflows/{workflow_id}/participants` (enhanced)
Now supports 3 modes:
**Mode A — Existing user by ID** (unchanged):
```json
{ "user_id": "uuid", "is_contract_principal": true }
```
**Mode B — Existing user by email:**
```json
{ "email": "cp@example.com", "name": "Jane Doe", "is_contract_principal": true }
```
→ Links user, creates org_access if needed. Returns participant object.
**Mode C — New user (triggers invite):**
```json
{
"email": "new@example.com",
"name": "John Doe",
"is_contract_principal": true,
"message": "Please review and sign the NDA" // optional, included in invite email
}
```
→ Returns:
```json
{ "status": "invited", "email": "new@example.com", "expires_at": 1740000000.0 }
```
**Validation:** Must provide either `user_id` OR (`email` + `name`).
### `GET /v1/workflows` (auto-filtered for CPs)
No frontend change needed. When a COUNTERPARTY user calls this, the backend automatically filters to only workflows they participate in.
### `POST /v1/invites` (new field)
```json
{
"email": "...",
"name": "...",
"role": "COUNTERPARTY",
"org_id": "uuid", // required for COUNTERPARTY
"workflow_id": "uuid" // optional — auto-adds as participant on accept
}
```
### `POST /v1/invites/accept` (new response field)
Response now includes:
```json
{
"user_id": "...",
"email": "...",
"role": "COUNTERPARTY",
"org_id": "uuid",
"workflow_id": "uuid", // NEW — present for COUNTERPARTY accepts
"access_token": "...",
"refresh_token": "..."
}
```
Use `workflow_id` to redirect the CP straight to their workflow after onboarding.
---
## Frontend Routing Suggestions
1. **Accept invite page** (`/accept-invite?token=...`):
- After successful accept, if `role === "COUNTERPARTY"` and `workflow_id` exists, redirect to `/workflows/{workflow_id}` instead of dashboard.
2. **Add participant modal** (on workflow detail):
- Add email + name fields alongside existing user picker
- Optional message textarea for invite email
- Handle two response shapes: participant object vs `{ status: "invited" }`
3. **Workflow detail — approve button**:
- Show "Ready to Sign" button for COUNTERPARTY participants who haven't approved yet
- Call `POST /v1/workflows/{id}/participants/approve`
- Refresh workflow status after (may have auto-transitioned to READY_TO_SIGN)
4. **Navigation scoping**:
- COUNTERPARTY users should see minimal nav — just Workflows (they're auto-filtered)
- Hide Cases, Organization settings, Credits, Bookings, etc.
---
## Status Transition Change
`FINALIZED → READY_TO_SIGN` is no longer a manual transition.
It's auto-triggered when all contract principals approve AND `signed_draft_id` is set.
`FINALIZED → SIGNED` still works for direct signing (skip eSign flow).
---
## New DB Migration
`0059_add_counterparty_and_access_type` — runs automatically on deploy.
- Adds `COUNTERPARTY` to role enum
- Adds `access_type` column to `org_access` (existing rows default to `MEMBER`)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment