Skip to content

Email a customer a portal sign-in link

The portal.login_links.request operation: POST /api/v1/public/{brandSlug}/portal/login_links in the REST API and the portal_login_links_request tool in the MCP server.

POST/api/v1/public/{brandSlug}/portal/login_links

Emails a one-time sign-in link for the brand's customer portal to the address, if it belongs to a customer of the brand in the portal's mode. The link works once, for 15 minutes; only a hash of its token is stored.

The answer is the same whether or not the address belongs to a customer, so nobody can find out who the brand's customers are. Requests are limited per address (5 per 15 minutes per brand) and per client IP (20 per hour), whether or not the address is known (rate_limited).

Public: the portal's sign-in page calls it, no API key needed.

At a glance

  • REST: POST /api/v1/public/{brandSlug}/portal/login_links
  • MCP tool: portal_login_links_request
  • Operation ID: portal.login_links.request
  • Scope: Brand
  • Permission: portal:write
  • Risk tier: write
  • Dry run: Not supported
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: None (a public endpoint, rate-limited per IP address)
  • Since: M9

Request

Path parameters

FieldTypeDescription
brandSlugstringThe brand's slug, as in /portal/{brandSlug}.

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
emailstringYesThe address the customer uses with the brand.

Response

200 OK with a JSON object:

FieldTypeDescription
object"portal_login_link_request"
emailstring
messagestringThe same answer whether or not the address belongs to a customer (nothing is revealed).

Examples

HTTP
POST /api/v1/public/genno/portal/login_links
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "email": "ana@example.com"
}

Response (200):

JSON
{
  "object": "portal_login_link_request",
  "email": "ana@example.com",
  "message": "If ana@example.com belongs to an account with Genno, we've sent it a sign-in link. The link works once, for 15 minutes."
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400email isn't an email address, or brandSlug isn't a slug.Fix the fields listed in details.issues and send the request again.
resource_not_found404No brand with this slug has a customer portal (draft and suspended brands have none).Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
rate_limited429Too many sign-in links were asked for this address (5 per 15 minutes per brand) or from this client IP (20 per hour); wait retry_after_ms.Wait for retry_after_ms and retry with backoff.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, scope_required, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, dry_run_not_supported, internal_error.