Skip to content

Search documentation

Try “webhook signature” or “amountUsd”. Use Tab or arrow keys to explore results.

    Open app
    Open app

    Documentation navigation

    Checkout sessions

    One server-created purchase attempt, scoped to a store and mode.

    On this page

    Create a checkout session

    POST/v1/profiles/{profileId}/checkout-sessions

    Authentication: Bearer key · Required scope: invoices.write

    Returns 201 for a new attempt, 200 for an exact retry. Requires a merchant store with billing details, wallet and accepted tokens ready.

    The published Node package does not expose these methods yet. Use HTTP.

    Path parameters
    FieldDetails
    profileIdpath · required UUIDThe profile that owns your API key.
    JavaScript
    const response = await fetch(
      process.env.FORWEND_API_URL + "/v1/profiles/" +
        process.env.FORWEND_PROFILE_ID + "/checkout-sessions",
      {
        method: "POST",
        headers: {
          Authorization: "Bearer " + process.env.FORWEND_KEY,
          "Content-Type": "application/json",
          "Idempotency-Key": "order-1042-attempt-1",
        },
        body: JSON.stringify({
          storeId: process.env.FORWEND_STORE_ID,
          amountUsd: "1250.00",
          reference: "order-1042",
          metadata: { order_id: "1042" },
        }),
      },
    );
    if (!response.ok) throw new Error("Checkout could not be created");
    const session = await response.json();
    // Send only the hosted URL, or the pay token for an embedded checkout, to your browser.
    const hostedUrl = session.payment.hostedUrl;
    const payToken = session.payment.payToken;

    Request headers

    Request headers
    FieldDetails
    Authorizationheader · requiredBearer followed by your server-only API key.
    Content-Typeheader · requiredapplication/json for a create request.
    Idempotency-Keyheader · required for create1–255 UTF-8 bytes. Reuse the same key and normalized body for a retry.

    Create request body

    JSON body
    FieldDetails
    storeIdUUID · requiredMerchant store owned by this profile and allowed by the key.
    amountUsdstring · requiredExact positive USD decimal. Compute it on your server.
    referencestring · optionalImmutable order reference; up to 100 characters.
    titlestring · optionalPurchase title; up to 200 characters.
    expiresIninteger · optional900–31536000 seconds.
    returnUrlstring · optionalHTTPS URL on one of the store’s allowed origins. A redirect is not payment proof.
    customerobject · optionalname (≤200 characters) and email.
    itemsarray · optionalUp to 100 {description, quantity, unitPrice} entries. Description ≤200; positive quantity with ≤2 decimals; USD unitPrice. Totals must match amountUsd.
    metadataobject · optionalUp to 20 single-line string values; see request rules.

    Read a checkout session

    GET/v1/profiles/{profileId}/checkout-sessions/{sessionId}

    Authentication: Bearer key · Required scope: invoices.read

    Returns 200 with canonical session state. No request body. Another store’s or mode’s session is hidden with 404.

    Read a checkout session
    FieldDetails
    profileIdpath · required UUIDThe profile that owns your API key.
    sessionIdpath · required stringIdentifier returned by create.

    List checkout sessions

    GET/v1/profiles/{profileId}/checkout-sessions

    Authentication: Bearer key · Required scope: invoices.read

    Returns 200 with {items, nextCursor}. Items are session objects, newest first. Includes attempts without invoice numbers. No request body.

    List checkout sessions
    FieldDetails
    profileIdpath · required UUIDThe profile that owns your API key.
    limitquery · integer1–100; default 50.
    cursorquery · stringThe previous response’s nextCursor. Omit for the first page.
    storeIdquery · UUIDOptional store filter, still limited by the key’s store.

    Expire an unpaid attempt

    POST/v1/profiles/{profileId}/checkout-sessions/{sessionId}/expire

    Authentication: Bearer key · Required scope: invoices.write

    No request body. Returns 200 with the closed session and is idempotent once expired. Payment already seen or confirming returns 409.

    Later funds remain held for the payer. Expiration does not erase receive addresses or financial records.

    Expire an unpaid attempt
    FieldDetails
    profileIdpath · required UUIDThe profile that owns your API key.
    sessionIdpath · required stringThe session to expire.

    Session response

    Changed purchase terms with the same idempotency key return 409 idempotency_conflict. Missing billing details return 409 billing_details_required.

    Session response
    FieldDetails
    sessionIdstringPurchase attempt identifier.
    statusstringopen, complete or expired. Read paymentStatus to determine whether the order is paid.
    payment.paymentId, reference, storeIdstring / nullable stringsThe payment and its original order/store relationship.
    payment.hostedUrlstring | nullHosted checkout URL to redirect the customer to.
    payment.payTokenstring | nullThe public pay token, the URL's last segment, for @forwend/js and @forwend/react.
    payment.chainId, token, amount, symbol, decimalstoken and money fieldsAmount is a string in integer base units; identify money by chain and contract.
    payment.paymentStatus, settlementStatus, refundStatusstringsSeparate payment, wallet settlement and held-money processing.
    payment.livemode, confirming, closedbooleansMode, pending network confirmation and whether checkout has closed.
    payment.receiptsarrayPer-option chainId, token, symbol, decimals, received, pending and held integer strings.
    payment.amountsobject · optionalExact receiver, payable, held, settled and refunded balances, with reconciliation information.

    Errors

    Responses use {error: {code, message}}. Missing or invalid credentials return 401; missing scope or a different profile returns 403. Objects outside the caller’s store or mode are hidden with 404.

    Invalid values return 422 invalid_value. Rate limiting returns 429 rate_limited with Retry-After. A starting network can return 503 network_not_ready; an unexpected server error returns 500 internal.

    Forwend documentation Test first. Confirm on your server.