# Workspace ↔ Synchron Permits order handoff

## Ownership and numbers

- A new Workspace trip is `HH-` plus nine digits, for example `HH-123456789`.
- Synchron creates and keeps its own eight-digit order token, for example `33617802`.
- One Workspace trip maps to at most one Synchron order. That order may contain any number of state permit items. The two numbers are never substituted for one another.
- Older Workspace alphanumeric references remain valid for callbacks. Synchron-originated trips still use `HH-` plus the eight-digit Synchron token.

## Outbound request

Workspace calls the factory extractor when the RateCon is uploaded and synchronizes the trip, its documents, and its service requests to the factory. Workspace sends Synchron an order request email containing the Workspace trip reference, RateCon attachment or seven-day download link, contact, dimensions, and unit information when available. Later state-specific emails must be added to the **same** Synchron order identified by `workspace_trip_ref`. The email is the current order-creation channel; the factory has no implemented `/api/synchron/orders` creation route. Do not create an order by both email and API without a shared idempotency key.

Synchron must store `workspace_trip_ref` on its order and include it in full-records API responses (top-level field or `meta` key), so historical import also adopts the original Workspace trip.

## Return API for Synchron developer

Send `POST https://heavyhaulgbt.com/api/webhooks/synchron` with JSON. Use the actual deployed Workspace host if different. Configure the same random secret of at least 32 characters as `SYNCHRON_CALLBACK_SECRET` in both services. For each request, set:

- `X-Synchron-Timestamp`: current Unix time in seconds.
- `X-Synchron-Signature`: `sha256=` followed by lowercase hex HMAC-SHA256 of `<timestamp>.<raw JSON body>` using the shared secret.

The timestamp must be within five minutes. Generate a fresh timestamp/signature on every retry. Send an `order.created` event once the order is created, then one `permit.attached` event per attached state item. The permit URL must be a stable HTTPS PDF/PNG/JPEG URL on an approved Synchron host, accessible to the Workspace server. Send the same `item_id` on retries and updates.

```json
{
  "event": "order.created",
  "workspace_trip_ref": "HH-123456789",
  "synchron_order_token": "33617802",
  "synchron_order_id": "12474"
}
```

```json
{
  "event": "permit.attached",
  "workspace_trip_ref": "HH-123456789",
  "synchron_order_token": "33617802",
  "synchron_order_id": "12474",
  "item_id": "63560",
  "state_code": "AL",
  "permit_number": "AL-123",
  "permit_url": "https://permits.synchrontms.com/storage/uploads/permits/example.pdf",
  "effective_date": "2026-09-24",
  "expiration_date": "2026-09-30"
}
```

**Order people in the callback — pending on Synchron.** When `order.created` carries the order's people, the webhook will apply the same rule the import applies today (accounts become active participants and their Auto-Participants are added). Until then the import scripts do it.

The callback refuses unknown trips, conflicting order tokens, and unapproved URLs. It upserts the document and permit by Synchron item ID, asks the factory to extract the permit, calculates Workspace dimension warnings, and syncs the result to the factory. A 503 response means file retrieval or extraction failed; retry the same item with a fresh signature. A 409 means the identifiers conflict and needs investigation. A retry of a processed item returns success without creating a duplicate.

## Workspace deployment steps

1. Apply `supabase/migrations/0035_synchron_workspace_order_link.sql` and `supabase/migrations/0036_permit_dimension_alert_deliveries.sql` after the client's `0033_permit_cost.sql` and `0034_multi_role_modes.sql` migrations.
2. Set Workspace `NEXT_PUBLIC_APP_URL` to its real public host, and configure `HHA_API_BASE_URL`, `HHA_API_CLIENT_ID`, `HHA_API_CLIENT_SECRET`, and `SYNCHRON_CALLBACK_SECRET`.
3. Confirm the factory's `API_PLATFORM_CLIENTS` includes the Workspace client with `agent:order.query`, `extractor:ratecon.extract`, and `extractor:permit.extract` scopes.
4. Share only the callback URL, payload contract, and callback secret through a secure channel with the Synchron developer. Do not send the secret in the permit request email.
5. Test one Workspace trip with two state items and retry each callback. Confirm one Workspace trip, one Synchron order token, two permits, and appropriate warnings.

## Local dimension-alert demo

Run `npm run dev` and open `/dev-preview/dimension-alert`. The sample Georgia permit starts below the trip's overall width, height, and weight. Run the alert check twice to see the first-send and duplicate-suppression outcomes; select **Matching permit** to see the no-alert case. The page uses the Workspace dimension comparison and previews the default alert template without changing trip data.

To verify real email delivery, sign in with email-template admin access and use **Send test email** on that page. It sends only to the entered address through the saved alert template and email provider, marks the subject `[DEMO TEST]`, and includes no live trip link. It does not create a permit or delivery reservation. The demo page and test endpoint are available only in development; use the callback test above for a full Synchron-to-Workspace check.
