Creates a new HPP session with pre-populated field data.
POST
/api/hostedpaymentpages/sessions
deprecated
Requires: HostedPaymentPage.HppSessions, HostedPaymentPage.HppSessions.Create, merchant scope.
Send an `idempotencyKey` to make the call safe to retry: the same key with the same request body returns the session already opened rather than opening a second one, and the response's `idempotencyStatus` says which happened. Reusing a key with a different body is refused. The key is a request-body field; no `Idempotency-Key` header is read.
Example request
Every block below sends the same request. Replace {{BASE_URL}} with the address of the API you are calling and {{API_KEY}} with your own key.
The request body is a CreateHppSessionInput. See the Request body section below for its fields.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
suppressNulls
required |
query | boolean | If true, omit properties with null values. |
Request body
application/json
, required
| Field | Type | Description |
|---|---|---|
hostedPageId
required |
string (uuid) | The HPP configuration ID this session targets. Required. |
customerId
required |
string (uuid) | Optional trusted customer id the merchant binds to this session. When supplied, the session relates to exactly this one customer: customer resolution at consent-capture time uses this id exclusively and never falls back to the ambiguous cardholder-email find-or-create, and the resulting transaction's `InvoiceData.CustomerId` is stamped from it server-side. The id is validated at session-create time to exist, be active, and belong to the session's merchant; a missing, inactive/soft-deleted, or cross-merchant id is rejected. `null` (the default) preserves the historical anonymous behavior where the customer is found-or-created from the cardholder email collected on the form. nullable |
prefilledFields
required |
object | Pre-populated field key/value pairs used to pre-fill the payment form. Use one of the well-known field keys listed below, or an enabled merchant custom field name. Keys reserved for sensitive card data or internal identifiers are always rejected. Handling of an unrecognized custom-field key depends on whether the target page scopes its custom fields (see the hosted page's custom-field allow-list). When the page does NOT scope its custom fields, an unrecognized key is accepted but ignored when the form is rendered (unchanged behavior). When the page DOES scope its custom fields, a key that is not a well-known field and not one of the page's allowed custom fields is rejected at session create with an error naming the offending key. A custom field the merchant has configured to accept a value from this API without showing it to the payer is also accepted here. Its value is applied to the resulting transaction server-side, exactly as supplied, and the field is not rendered on the payment form. Because the payer never sees it and nobody can correct it later, the value is validated against the field's own rules (maximum length, regular expression, numeric range) at session create: a value that breaks one of them is rejected here rather than being carried and dropped at payment time. Conditional: Conditional (see validator source). Conditional: When AmountMode == Suggested. Conditional: When LockShippingAddress is true. Conditional: When PrefilledFields is not null. Valid keys (in addition to enabled merchant custom field names): - `allowed_payment_methods`: Comma-separated list of payment-method keys the session permits (e.g. `card,ach`). A directive, not a form field: it narrows the page's rendered payment methods for this session (intersection with the page's configured + capability-filtered methods). Empty or absent means no session-level restriction. Values must be recognized payment-method keys; session creation rejects unrecognized entries - `base_amount`: Base transaction amount - `billing_address1`: Billing address line 1 - `billing_address2`: Billing address line 2 - `billing_city`: Billing city - `billing_country`: Billing country - `billing_first_name`: Billing first name - `billing_last_name`: Billing last name - `billing_phone`: Billing phone number - `billing_state`: Billing state or province - `billing_zip`: Billing ZIP or postal code - `convenience_fee`: Convenience fee amount. Pins the fee on a session whose amount mode is Locked; on any other amount mode the page ignores it and applies the merchant's configured fee - `customer_email`: Customer email address - `invoice_number`: Invoice number - `order_summary`: JSON-serialized order summary containing line items and totals. Used to render a detailed summary panel on the payment page. Value must be a valid `HppOrderSummaryDto` JSON string - `po_number`: Customer code / purchase order number. Applied to `Level2Data.PoNumber` (max 25 characters, alphanumeric), the same slot the Virtual Terminal writes. Gated by the page's `FieldPurchaseOrder` visibility exactly as `InvoiceNumber` is gated by `FieldInvoice` - `promo_code`: A promotion code the link carries, so a merchant can send a payer a link that arrives with the discount already in the box. It is a <b>suggestion</b>, not a grant: the surfaces still evaluate it server-side against the promotion the merchant owns, and a code that no longer applies is refused exactly as a typed one is. Nothing about a prefilled code is trusted, which is why it can safely ride a URL a payer can edit - `shipping`: Shipping amount - `shipping_address1`: Shipping address line 1 - `shipping_address2`: Shipping address line 2 - `shipping_city`: Shipping city - `shipping_country`: Shipping country - `shipping_first_name`: Shipping first name - `shipping_last_name`: Shipping last name - `shipping_phone`: Shipping phone number - `shipping_state`: Shipping state or province - `shipping_zip`: Shipping ZIP or postal code - `suppress_convenience_fee`: Declares that this session authoritatively carries <b>no</b> convenience fee, so the public surfaces must neither seed one from the merchant's convenience-fee configuration nor recompute a percentage one, and must render no fee line and no disclosure block. A directive, not a form field: it states a producer's decision rather than a value the payer sees. Must be one of the `HppConvenienceFeeSuppressionPolicy` values (`true`, `false`); session creation rejects anything else. Absent means no declaration, which is the pre-directive behaviour: the surfaces resolve the fee themselves - `surcharge`: Surcharge amount - `tax`: Tax amount - `tip`: Tip amount - `vault_restriction`: Vault-restriction directive controlling how the payment instrument may be stored for this session. Must be one of the `VaultRestrictionValues` constants (`any`, `allow_new_and_saved`, `saved_only`). A directive, not a form field. Absent means no restriction (`any`) nullable |
prefilledListFields
required |
object | Optional list-valued prefills for the merchant's multi-value custom fields, keyed by the custom-field name. Each key must name a merchant custom field flagged multi-value; a key that names a single-value field, a well-known field, a blocked key, or a key also present in `prefilledFields` is rejected. The list is checked against the field's own rules (value cap, maximum length per item, regular expression) at session create, and every item must be non-empty. The payer sees the values read-only, one per line, and the resulting transaction carries them as `customFields[].values`. A field configured to accept a value from this API without showing it to the payer is accepted here too and stamped server-side. Conditional: When PrefilledListFields is not null. nullable |
expirySeconds
required |
integer (int32) | Requested session TTL in seconds. If `null`, the default for the resolved `linkLifetime` is used. Must be within the bounds that lifetime allows, and must be omitted entirely for `Permanent`, which has no expiry to set. Conditional: When ExpirySeconds is not null. nullable |
linkLifetime
required |
all of HppLinkLifetime | How long this payment link stays payable. `Session` (the default) is the historical short single-use checkout session: 60 to 900 seconds, defaulting to 600, still capped by the tenant's own TTL settings. `Extended` widens the window to 1 hour through 90 days for a link that is emailed or texted and paid later. `Permanent` mints a link with no expiry at all, which stops being payable only when it is paid, cancelled, or revoked. |
correlationId
required |
string | Optional merchant-supplied correlation ID for tracing/debugging. Conditional: When CorrelationId is not null. Max length: 200. nullablemax length 200 |
label
required |
string | Optional human-readable label for identifying this session (e.g., "Invoice #1234"). Conditional: When Label is not null. Max length: 100. nullable |
cancelUrl
required |
string | Optional address the payer's Back link returns to from the payment form, before paying, such as your cart page. Overrides the page's own `PageActions.Cancel` address for this session. Conditional: When CancelUrl is not empty. Max length: 200. nullable |
inactiveMessage
required |
string | Optional plain-text message a payer sees instead of the generic out-of-service copy once this link is paused, or once a reusable link has filled its completion cap. nullablemax length 500 |
idempotencyKey
required |
string | Optional caller-supplied key that makes this create safe to retry. Send the same key with the same request body and the gateway returns the session it already opened instead of opening a second one, so a timeout or a network retry cannot leave you with two payment links for one order. Conditional: When IdempotencyKey is not empty. nullable |
requestedCredentialStorage
required |
all of StoredCredentialUsage | Optional. Declares that the merchant intends to capture stored-credential consent on this session. When set, the HPP checkout page renders the consent prompt; whether the cardholder must tick it before submitting is governed by `requireConsent` (or the tenant default when that is unset). `null` or `None` leaves the prompt off. The flags describe the permitted usage scopes the cardholder is being asked to consent to (`Recurring`, `Installment`, `UnscheduledCOF`, `OneTimeFuture`) and are persisted on the resulting `StoredCredentialConsent` record. Values combine: send one or more member names separated by a comma and a space, or the integer sum of their values. Responses carry the names. nullable |
requireConsent
required |
boolean | Optional per-session override for whether ticking the stored-credential consent box is mandatory before the payment can be submitted. `null` (the default) inherits the tenant-level `StoredCredentialConsents.RequireConsent` setting, preserving historical behavior. `true` forces consent to be required for this session (the cardholder must tick the box to pay); `false` makes it optional (the box is still shown, but the cardholder may submit a normal sale without ticking it: no token is vaulted and no consent record is written when they decline). nullable |
declineRetryMode
required |
all of HppDeclineRetryMode | Optional per-session override of what this payment link does when the processor declines a payment. `null` (the default) resolves the policy from the targeted hosted page and then the tenant default, which is the historical single-use behavior. Conditional: When DeclineRetryMode is not null. nullable |
tokenizeOnPayment
required |
boolean | Optional: declares whether the cardholder's card should be vaulted as a reusable `PaymentToken` when this session's payment succeeds. `null` (the default) defers to the merchant's `MerchantFeatureSettings.HppTokenizeOnPaymentDefault` flag; `true` forces tokenization on for this session; `false` forces it off regardless of the merchant default. nullable |
saveCardOnly
required |
boolean | Optional: when `true`, this session saves the cardholder's card <b>without</b> charging it: the gateway runs a zero-dollar account verification (authorize $0 + AVS/CVV, immediate void) instead of a payment, then vaults the card and captures consent. Used for "save card now, charge later" onboarding / add-card-to-wallet. Default `false` (a normal chargeable session). nullable |
parentOrigin
required |
string | Optional HTTPS origin (scheme + host, e.g. `https://shop.example.com`) of the parent page that will embed this HPP session in an iframe. When set, the HPP page emits `postMessage` lifecycle events (`ready`, `session_loaded`, `payment_succeeded`, etc.) using this value as the `targetOrigin`; never `'*'`. The host portion must match an entry in the resolved page's `AllowedEmbeddingDomains` (wildcard subdomains supported). When `null`, postMessage emission is disabled (fail-closed) and the iframe still works for non-embedded use. Conditional: When ParentOrigin is not empty. Max length: 2048. Conditional: When HostChannel == NativeWebView. nullable |
enableFieldEvents
required |
boolean | Optional opt-in to per-field `field_focused` / `field_blurred` postMessage events. When `true`, the iframe attaches a single delegated focus/blur listener on the form root and emits one envelope per focus boundary with the element's `data-hpp-field` identifier. <strong>Field values are NEVER included.</strong> When `false` (the default) no listener is registered, so there is no JS boundary at which a value could leak. Requires `parentOrigin` to be set: otherwise the emitter is fail-closed and emits nothing regardless of this flag. |
presentationMode
required |
all of HppPresentationMode | How the public page presents itself for this session. `Standalone` (the default) renders the full standalone page exactly as today. `Embedded` renders a chrome-less compact surface intended for mounting inside a merchant-site iframe: no standalone page background or full-viewport height, tight paddings, and narrow-width behavior that stays readable at 320 px without horizontal scrolling. |
hostChannel
required |
all of HppHostChannel | Where this session delivers its `postMessage` lifecycle envelopes, and where it accepts commands from. `ParentWindow` (the default) is the historical iframe integration: envelopes go to `window.parent` targeted at `parentOrigin`. `NativeWebView` is for a native iOS, Android or Flutter app that loads the page in a WebView, where envelopes go to the single message handler the host app installed instead. |
purpose
required |
all of HppSessionPurpose | Classifies the calling context that produced this session, which selects the allowed TTL bounds and any other purpose-specific policy. Defaults to `CheckoutLink`: the historical merchant-facing pay-link behavior with a 15-minute TTL ceiling. |
level3Data
required |
all of Level3Data | Optional Level 3 commercial-card data: header fields (PO/invoice numbers, ship-from / destination ZIPs, freight/duty/discount) plus a list of line items. When supplied, the data is persisted on the session, surfaced read-only on the HPP for the cardholder, and forwarded onto the resulting `Transaction.Level3Data` so the existing TSYS L3 interchange-qualification mapping consumes it unchanged. `null` (the default) preserves the historical L2-only flow. Conditional: When Level3Data is not null. |
pagePurpose
required |
all of HppPagePurpose | Optional per-session override for the targeted page's purpose. `null` (the default) uses the page's own purpose, so existing integrations are unaffected. A non-null value takes precedence, letting one page back Payment, SaveCard, and SaveCardWithInitialCharge sessions without maintaining parallel page instances. Conditional: When PagePurpose is not null. nullable |
recurringPlan
required |
all of HppRecurringPlan | Optional per-session recurring definition, used only when the resolved `pagePurpose` is `SaveCardWithInitialCharge`; it then overrides the page's inlined plan. Required (from this override or the page) for that purpose and validated for complete economics. Supplying it for any other resolved purpose is rejected. Conditional: Conditional (see validator source). |
captureMode
required |
all of HppCaptureMode | Optional per-session capture-mode override for the chargeable Payment flow. `Sale` authorizes and captures now (the default; `null` uses the page value); `Authorize` authorizes now and defers capture. Only valid on the Payment purpose; an explicit Authorize override against a card-capture purpose is rejected. Conditional: When CaptureMode is not null. Conditional: When IsCardCapture(PagePurpose) is true. nullable |
amountMode
required |
all of HppSessionAmountMode | How this session treats the payment amount, overriding whether the targeted page would let the cardholder set it. `CustomerEntered` (the default) leaves the page's own amount behavior in charge; `Suggested` pre-fills an editable amount (e.g. a suggested donation); `Locked` pre-fills a read-only amount the cardholder cannot change (e.g. paying an invoice) that the server verifies on submit. The amount value is supplied via the `base_amount` prefilled field. Conditional: Conditional (see validator source). Must equal CustomerEntered. |
lockShippingAddress
required |
boolean | Optional. When `true`, the shipping address supplied through the `shipping_*` prefilled fields is shown to the payer display-only: they cannot edit it on the hosted page, and the transaction records that address whatever the submit carried. `false` (the default) keeps the historical behavior, where a prefilled shipping address is a starting value the payer may change. |
customerEmailVisibility
required |
all of HppFieldVisibility | Optional per-session override for whether the payer-facing customer-email field is collected. `null` (the default) inherits the targeted page's own `FieldCustomerEmail` configuration, which is what every existing integration gets. `Hidden` drops the field on a page that shows it, `Optional` shows it without demanding a value, and `Required` shows it and blocks submit until it is filled, even on a page that hides it. One page can therefore serve both a known-customer flow and an anonymous email-matched flow without a second page configuration. Conditional: When CustomerEmailVisibility is not null. nullable |
campaignId
required |
string (uuid) | Optional campaign this payment link belongs to. Omit it and the session inherits the targeted page's own campaign, so a merchant can attach a page to a campaign once instead of naming the campaign on every link it issues. Supply a value and it wins over the page's. nullable |
reusable
required |
boolean | Whether this link accepts many payers rather than one. Defaults to `false`, which is the single-use link every caller written before this field existed asks for. |
maxCompletions
required |
integer (int32) | How many payments a reusable link accepts before it closes, or `null` for a link that keeps accepting payers until it is revoked or expires. nullable |
currency
required |
string | Optional ISO 4217 currency code this link is denominated in, for example `USD`. Omit it and the session takes the merchant's own configured currency, which is what every link got before this field existed. Either way the created session reports the currency it settled on, so an integrator can read it back rather than infer it. Conditional: When Currency is not null. nullablemax length 3 |
campaignSource
required |
string | Optional per-channel source tag for this link: `email`, `sms`, `qr`, `social`, or whatever short label names the channel you are issuing it through. Mint one link per channel with a different tag and the campaign report compares them side by side. Conditional: When CampaignSource is not null. nullablemax length 32 |
products
required |
array of HppSessionProductInput | Optional cart for a page that sells catalog products: the products to start the order at and their quantities. Each entry must name a product on the page. A quantity of zero leaves an optional product out; a required product cannot be left out. Products the cart does not mention start at the page's default quantity. Rejected on a page that sells no products. Conditional: When Products is not null. nullable |
This request body has no documented fields.
Responses
200 OK
Body: HppSessionCreatedDto
Each item has these fields.
| Field | Type | Description |
|---|---|---|
sessionId
required |
string (uuid) | The unique session identifier. |
shortToken
required |
string | The short URL token for this session (12-character Base62). nullable |
hppUrl
required |
string | The absolute HPP payment-link URL using the short token, resolved against the platform's configured public base URL (`HostedPaymentPage:PublicBaseUrl`, falling back to `App:SelfUrl`). Example: `https://pay.example.com/pay/s/aB3kX9mZqR`. Callers can use it directly without resolving it against the host they requested from. nullable |
expiresAt
required |
string (date-time) | UTC timestamp when the session will expire, or `null` when the session was created with the `Permanent` lifetime and never expires on its own. Only a request that explicitly asked for that lifetime can receive `null` here. nullable |
correlationId
required |
string | The correlation ID echoed back from the request, if provided. nullable |
idempotencyStatus
required |
all of HppSessionCreateIdempotencyStatus | What the `idempotencyKey` on the request actually did. `Replayed` means this response is a session that already existed and nothing new was created; `KeyIgnored` means the key was accepted but bought nothing, because create idempotency is not enabled for this merchant. Always populated. |
label
required |
string | The label echoed back from the request, if provided. nullable |
cancelUrl
required |
string | The Back link address stored on the created session, if one was supplied. nullable |
effective
required |
all of HppSessionEffectiveShapeDto | The shape the server actually resolved this session into, read off the created session rather than off the request. Several inputs are legitimately accepted and then overridden (a card-capture purpose forces required consent, a page can veto tokenization, a fixed-amount page derives an amount mode, a credential-storage scope is defaulted or widened), and the call still returns 2xx either way. Read this block to confirm the session is shaped the way you intended, instead of loading the hosted page and inspecting it. |
This response has no documented body fields.
409 The idempotency key was already used for a different request (`HostedPaymentPage:HppSession:CreateIdempotencyKeyReused`), the create it belongs to is still running (`HostedPaymentPage:HppSession:CreateIdempotencyInProgress`), or the key can no longer be resolved to a session and so cannot answer for it again (`HostedPaymentPage:HppSession:CreateIdempotencySessionGone`, which calls for a new key rather than a retry). Nothing was created in any of the three.
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
403 Forbidden
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
401 Unauthorized
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
400 Bad Request
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
404 Not Found
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
501 Not Implemented
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
500 Internal Server Error
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
default The request failed. The body carries the standard error envelope: a machine-readable `error.code`, a human-readable `error.message`, and `error.validationErrors` when the failure was a validation rejection. See the error-code reference in this document's description for the values `error.code` can take.
Body: RemoteServiceErrorResponse
Each item has these fields.
| Field | Type | Description |
|---|---|---|
error
required |
RemoteServiceErrorInfo |
This response has no documented body fields.
429 The request was refused because a rate limit was exceeded. Wait at least the interval `Retry-After` names before retrying, then back off. Limits are tuned per deployment, so read the allowance from the response headers rather than assuming a fixed ceiling.
Body: RateLimitProblemDetails
Each item has these fields.
| Field | Type | Description |
|---|---|---|
type
required |
string | The problem type identifier. Always the same value: the failure is the status code itself, so there is no sub-type for a caller to branch on. nullable |
title
required |
string | A short, human-readable summary of the problem type. nullable |
status
required |
integer (int32) | The HTTP status code, repeated in the body as the problem-details format defines. |
detail
required |
string | A human-readable explanation of this occurrence of the problem. nullable |
retryAfterSeconds
required |
integer (int32) | How long to wait before retrying, in whole seconds, carrying the same figure as the `Retry-After` header. Always at least one: a value of zero would invite an immediate retry that is certain to be rejected again. |
This response has no documented body fields.
Errors
A failed request returns the platform error envelope. The
error reference lists every value
error.code can carry and shows the four response shapes.