Vendor email portal
The portal lets a vendor answer your security questionnaire without creating an account. Covenant generates a signed, expiring magic-link; the vendor fills it in; you import the result. The scoring is identical to the in-app questionnaire.
What the link is
The link looks like portal.html#<signed-token>. The token after the # is a string of the form <claims>~<signature> that binds:
- the vendor and the questionnaire template,
- the issued time and an expiry (default 14 days),
- a one-time nonce so two sends never collide,
- a signature over all of the above.
Because it is signed, a link that has been altered or expired is rejected. Because the claims travel in the URL, the vendor needs no login.
Sending it
- Open the vendor → Security questionnaire card → pick a template → Send to vendor portal.
- Covenant mints the token, generates the link, and attempts to send it plus the reminder cadence through the notification service.
- A confirmation tells you whether it was sent live (cloud, target shown masked) or simulated locally, how many reminders were queued, and the expiry date.
- The vendor detail now shows a Signed vendor portal link banner with an open portal ↗ link, the expiry, and the next reminder date.
Reminder cadence
An outstanding request follows this schedule: an initial send at issue, then reminders at +3, +7, and +12 days. Reminders stop automatically once the token expires or the response is captured. The banner shows the next reminder date; the Re-send / remind now button fires one immediately.
| Event | When |
|---|---|
| Initial request | At send |
| Reminder 1 | +3 days (if before expiry) |
| Reminder 2 | +7 days (if before expiry) |
| Reminder 3 | +12 days (if before expiry) |
| Stop | On response captured, or at expiry |
The vendor's experience (no account)
When the vendor opens the link, the portal page:
- Verifies the link's structure and expiry. If expired or malformed, it shows a friendly "this link can't be opened" message asking them to request a fresh one.
- Loads the right questionnaire template and renders it, honoring conditional questions.
- Shows live progress ("X/Y in-scope questions answered", current pass-%).
- On Submit response, produces a response code and asks the vendor to send it back (in production this returns to you automatically; in the local demo they copy and paste it).
Importing the response
- Get the response code from the vendor (the long string the portal produced).
- On the vendor's Security questionnaire card, paste it into "Paste the vendor's response code to import answers".
- Click Import response.
Covenant checks that the code matches this vendor's current link and template, and that the link is still valid (signature + not expired). On success, the answers populate and the score updates. On failure you get a precise reason — see the table below.
| Message | Cause & fix |
|---|---|
| "That doesn't look like a valid response code." | The pasted text is corrupted or truncated. Ask the vendor to re-copy the whole code. |
| "This response code is for a different/expired questionnaire link." | The code is from an older link (you re-sent since). Use the latest code, or re-send and have them refill. |
| "This response is for a different questionnaire template." | You changed the template after sending. Re-send the intended template. |
| "Cannot import: this questionnaire link is no longer valid (…). Re-send a fresh link." | The link expired or was tampered. Click Send to vendor portal again to mint a fresh 14-day link. |
Token validity & expiry
- Default lifetime: 14 days from issue.
- Single-use intent: the token carries a nonce and the assessment marks it captured on import; re-sending mints a brand-new token.
- Tamper protection: any change to the link's claims breaks the signature and the response will be refused on import.
- Per-install secret: a token minted by one Covenant install will not verify in another — the signing secret is per install (standing in for the per-tenant secret the hosted send runner will own).
/portal/:token, validates the signature and single-use server-side before rendering, and the email is actually delivered. Today everything except live delivery and server-side signature validation runs in your browser — and the security semantics (sign → verify → expiry → single-use) are real and enforced.