Skip to content

Generate a customer portal link

The portal.sessions.create operation: POST /api/v1/portal/sessions in the REST API and the portal_sessions_create tool in the MCP server.

POST/api/v1/portal/sessions

Makes a one-time sign-in link to the brand's customer portal for one customer, in the request's mode: send the customer there (for example from your own app's billing page). The link works once, for 15 minutes; the customer's session then lasts 7 days.

Generating a link doesn't sign you in: whoever opens it is signed in as the customer, so give it only to them. Generating it is recorded in the audit log with who asked. Only a hash of the link's token is stored. Needs customers:write.

At a glance

  • REST: POST /api/v1/portal/sessions
  • MCP tool: portal_sessions_create
  • Operation ID: portal.sessions.create
  • Scope: Brand
  • Permission: customers:write
  • Risk tier: security
  • Dry run: Not supported
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the customers:write scope
  • Since: M9

Request

Body

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

FieldTypeRequiredDescription
customerIdcus_… IDYesThe customer the link signs in (cus_…).

Response

201 Created with a JSON object:

FieldTypeDescription
object"portal_session_link"
idpsess_… ID
customerIdcus_… ID
livemodeboolean
urlstringThe one-time sign-in link to give the customer. It works once, for 15 minutes; only its hash is stored.
expiresAtdate-timeThe link stops working then.

Examples

HTTP
POST /api/v1/portal/sessions
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf48b1"
}

Response (201):

JSON
{
  "object": "portal_session_link",
  "id": "psess_01m4tx5nj8emwbyf7y9vcf48b2",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf48b1",
  "livemode": false,
  "url": "https://ownrecord.io/portal/genno/login/verify?session=psess_01m4tx5nj8emwbyf7y9vcf48b2&token=Q2hhbmdlTWVJbkV4YW1wbGVzT25seS4uLi4uLi4uLi4",
  "expiresAt": "2026-10-20T09:15:00.000Z"
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400customerId isn't a customer ID (cus_…).Fix the fields listed in details.issues and send the request again.
resource_not_found404This brand has no such customer in this mode (customers belong to one brand and one mode).Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
customer_deleted400The customer was deleted.Create a new customer for this buyer. Deleted customers stay readable for the records they belong to, but can't be changed.
scope_required400The request names no brand (an org or entity key without Ownrecord-Brand).Call the operation with credentials or a target at its level: an organization, a legal entity, a brand or the platform (details.required_scope).
livemode_not_allowed403You have no live-mode access, so you can't act on live customers.Use test mode, or credentials for the target's mode. Developers need live access granted by an organization owner or admin.
permission_denied403You can't change this brand's customers (customers:write: owners, admins and support).Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, dry_run_not_supported, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.