Docs
Sessions API

Sessions API

Manage form submission sessions, contact data, and checkout flows.

The Sessions API allows you to create and manage form submission sessions for your organization. Sessions track user interactions through multi-step forms, contact information collection, and checkout processes.

Session Object

A session represents a user's journey through a form submission with the following structure:

{
  "success": true,
  "data": {
    "sessionId": "550e8400-e29b-41d4-a716-446655440000",
    "submissionId": "sub_cmg4x57yp0018r9p7q73eghxb",
    "formId": "form_456def"
  }
}

Session Data Structure

When retrieving session data:

{
  "contact": {
    "email": "john.doe@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "phone": "+1234567890"
  },
  "answers": {
    "weight": "185",
    "height": "5'10\"",
    "goal": "weight_loss",
    "medications": ["metformin", "vitamin_d"]
  }
}

Create Session

Create a new form submission session.

POST /api/sessions

Headers

HeaderRequiredDescription
X-API-KeyYesYour API key for authentication
Content-TypeYesMust be application/json

Request Body

{
  "formId": "550e8400-e29b-41d4-a716-446655440000",
  "formTitle": "Weight Management",
  "formDescription": "TrimRx Weight Management Form",
  "locale": "EN_US",
  "sourceURL": "https://example.com/landing-page",
  "clientIp": "192.168.1.1",
  "userAgent": "Mozilla/5.0...",
  "everflowTrackingId": "tracking_123",
  "standardTimezone": "America/New_York",
  "timezone": "EST"
}

Parameters

ParameterTypeRequiredDescription
formIdstring (UUID)NoExisting form ID to use as template
formTitlestringNoForm title (default: "Weight Management")
formDescriptionstringNoForm description (default: "TrimRx Weight Management Form")
localeenumNoLanguage code: EN_US, ES_ES, ES_MX, FR_FR, DE_DE, IT_IT, PT_BR, RU_RU, ZH_CN, JA_JP (default: "EN_US")
sourceURLstringYesURL where session originated
clientIpstringNoClient IP address for tracking
userAgentstringNoBrowser user agent
everflowTrackingIdstringNoEverflow tracking identifier
standardTimezonestringNoStandard timezone name
timezonestringNoTimezone abbreviation

Response

Status Code: 201 Created

{
  "success": true,
  "data": {
    "sessionId": "550e8400-e29b-41d4-a716-446655440000",
    "submissionId": "sub_cmg4x57yp0018r9p7q73eghxb",
    "formId": "form_456def"
  }
}

Example Request

curl -X POST "https://api.evon.com/api/sessions" \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceURL": "https://example.com/landing-page",
    "locale": "EN_US",
    "formTitle": "Weight Management Consultation"
  }'

Get Session Data

Retrieve current contact and answer data for a session.

GET /api/sessions/:session_id

Path Parameters

ParameterTypeRequiredDescription
session_idstring (UUID)YesThe unique identifier of the session

Headers

HeaderRequiredDescription
X-API-KeyYesYour API key for authentication
Content-TypeYesMust be application/json

Response

Status Code: 200 OK

{
  "contact": {
    "email": "john.doe@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "phone": "+1234567890"
  },
  "answers": {
    "weight": "185",
    "height": "5'10\"",
    "goal": "weight_loss",
    "mainMotivation": "health",
    "weightLossGoal": "20_30_lbs",
    "commitmentLevel": "very_committed"
  }
}

If no data has been submitted yet:

{
  "contact": null,
  "answers": null
}

Example Request

curl -X GET "https://api.evon.com/api/sessions/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json"

Update Session

Submit or update contact information and form answers for a session.

PUT /api/sessions/:session_id

Path Parameters

ParameterTypeRequiredDescription
session_idstring (UUID)YesThe unique identifier of the session

Headers

HeaderRequiredDescription
X-API-KeyYesYour API key for authentication
Content-TypeYesMust be application/json

Request Body

{
  "contact": {
    "email": "john.doe@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "phone": "+1234567890"
  },
  "answers": {
    "weight": "185",
    "height": "5'10\"",
    "goal": "weight_loss",
    "medications": ["metformin", "vitamin_d"],
    "mainMotivation": "health",
    "weightLossGoal": "20_30_lbs",
    "commitmentLevel": "very_committed"
  },
  "metadata": {
    "utm_source": "google",
    "utm_campaign": "summer_2025"
  },
  "attributions": {
    "ef_transaction_id": "ef_123",
    "fbclid": "fb_456",
    "ttclid": "tt_789",
    "ScCid": "sc_012",
    "affid": "aff_345",
    "affid2": "aff2_678"
  }
}

Parameters

ParameterTypeRequiredDescription
contactobjectNoContact information
contact.emailstringNoContact email address
contact.firstNamestringNoContact first name
contact.lastNamestringNoContact last name
contact.phonestringNoContact phone number
answersobjectNoForm answers as key-value pairs where values can be string, number, boolean, or array of strings
metadataobjectNoAdditional metadata to store with the submission
attributionsobjectNoAttribution tracking parameters

Response

Status Code: 200 OK

{
  "success": true,
  "data": {
    "submissionId": "sub_cmg4x57yp0018r9p7q73eghxb",
    "sessionId": "550e8400-e29b-41d4-a716-446655440000",
    "contactId": "contact_abc123",
    "formStepsCreated": 7
  }
}

Example Request

curl -X PUT "https://api.evon.com/api/sessions/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "contact": {
      "email": "john.doe@example.com",
      "firstName": "John",
      "lastName": "Doe"
    },
    "answers": {
      "weight": "185",
      "goal": "weight_loss"
    }
  }'

Partially Update Session

Update specific fields in a session without replacing all data.

PATCH /api/sessions/:session_id

Path Parameters

ParameterTypeRequiredDescription
session_idstring (UUID)YesThe unique identifier of the session

Headers

HeaderRequiredDescription
X-API-KeyYesYour API key for authentication
Content-TypeYesMust be application/json

Request Body

{
  "contact": {
    "phone": "+1987654321"
  },
  "answers": {
    "medications": ["semaglutide"]
  }
}

Response

Status Code: 200 OK

{
  "success": true,
  "data": {
    "submissionId": "sub_cmg4x57yp0018r9p7q73eghxb",
    "sessionId": "550e8400-e29b-41d4-a716-446655440000",
    "contactId": "contact_abc123"
  }
}

Session Checkout

Initiate the checkout process for a session with selected products. The endpoint creates both a PaymentIntent for immediate payment and a SetupIntent to save the payment method for future off-session charges.

POST /api/sessions/:session_id/checkout

Path Parameters

ParameterTypeRequiredDescription
session_idstring (UUID)YesThe unique identifier of the session

Headers

HeaderRequiredDescription
X-API-KeyYesYour API key for authentication
Content-TypeYesMust be application/json

Request Body

{
  "priceIds": ["price_asdf98asdf98as98sdf", "price_jgh09erg9f89fd9d"],
  "couponCode": "SUMMER2025"
}

Parameters

ParameterTypeRequiredDescription
priceIdsarrayYesArray of price IDs (at least one required)
couponCodestringNoStripe coupon code to apply discount

Response

Status Code: 200 OK

Without Coupon

{
  "success": true,
  "provider": "stripe",
  "intentType": "setup_and_payment",
  "clientSecret": "pi_3SOXZl9N4MgodpWp0dJHMvom_secret_XqydlIl4HY6NM6J2q3P9GBQ2a",
  "paymentIntentId": "pi_3SOXZl9N4MgodpWp0dJHMvom",
  "setupIntentId": "seti_1SOXZk9N4MgodpWpf6a3TWe4",
  "publicKey": "pk_test_51S5YAO9N4MgodpWpgtYpV8mm4mg1tWvSfhYYcidI8uTLpTvLGu9G2LD0Nd2YAUzckMPafmBFJUEarznYT0xz5BMC00AN9o8syA",
  "checkout": {
    "originalAmount": 2820,
    "finalAmount": 2820,
    "amount": 2820,
    "currency": "USD",
    "products": [
      {
        "id": "cmg4x571e000cr9p7qyk0otjt",
        "name": "Oral Tirzepatide",
        "price": 2820,
        "frequency": "ANNUAL"
      }
    ]
  },
  "session": {
    "id": "cbd94768-6af9-4094-90aa-00ec2f63b777",
    "contactId": "cmhf9w8pg000ypf6vsv6fk28w"
  }
}

With Coupon (JOIN120)

{
  "success": true,
  "provider": "stripe",
  "intentType": "setup_and_payment",
  "clientSecret": "pi_3SOXZl9N4MgodpWp0dJHMvom_secret_XqydlIl4HY6NM6J2q3P9GBQ2a",
  "paymentIntentId": "pi_3SOXZl9N4MgodpWp0dJHMvom",
  "setupIntentId": "seti_1SOXZk9N4MgodpWpf6a3TWe4",
  "publicKey": "pk_test_51S5YAO9N4MgodpWpgtYpV8mm4mg1tWvSfhYYcidI8uTLpTvLGu9G2LD0Nd2YAUzckMPafmBFJUEarznYT0xz5BMC00AN9o8syA",
  "checkout": {
    "originalAmount": 2820,
    "finalAmount": 2700,
    "amount": 2700,
    "currency": "USD",
    "coupon": {
      "code": "6BFwBJo4",
      "amountOff": 120,
      "discountAmount": 120
    },
    "products": [
      {
        "id": "cmg4x571e000cr9p7qyk0otjt",
        "name": "Oral Tirzepatide",
        "price": 2820,
        "frequency": "ANNUAL"
      }
    ]
  },
  "session": {
    "id": "cbd94768-6af9-4094-90aa-00ec2f63b777",
    "contactId": "cmhf9w8pg000ypf6vsv6fk28w"
  }
}

Response Fields

FieldTypeDescription
checkout.originalAmountnumberOriginal total amount before discount
checkout.finalAmountnumberFinal amount after applying coupon discount
checkout.amountnumberSame as finalAmount (for compatibility)
checkout.couponobjectCoupon details (only present if valid coupon was applied)
checkout.coupon.codestringThe coupon code that was applied
checkout.coupon.percentOffnumberPercentage discount (if applicable)
checkout.coupon.amountOffnumberFixed amount discount (if applicable)
checkout.coupon.discountAmountnumberActual discount amount applied

Coupon Behavior

The checkout endpoint supports both Stripe Coupons and Promotion Codes:

  • Promotion Codes: The API first attempts to find the code as a Stripe Promotion Code (most common)
  • Direct Coupons: If not found as a promotion code, it tries to retrieve it as a direct Stripe coupon
  • Automatic Application: Valid coupons automatically apply the discount to the payment amount
  • Graceful Failure: Invalid or expired coupons are silently ignored (checkout continues at full price)
  • Discount Types: Supports both percentage-based (percent_off) and fixed amount (amount_off) discounts
  • Minimum Amount: The final amount after discount must be greater than $0
  • Tracking: Coupon information is stored in PaymentIntent metadata and FormStep records for auditing
  • Response Data: The coupon object is only included in the response when a valid coupon is applied

Example Discount Calculation

For a $2820 annual subscription with JOIN120 coupon ($120 off):

  • Original Amount: $2820
  • Coupon Discount: -$120
  • Final Amount: $2700 (charged to customer)

The PaymentIntent is created for the discounted amount ($2700), ensuring the customer is only charged the final price.

Frequency Mapping

The checkout endpoint maps the new price schema to display frequencies:

  • type=ONE_TIME"ONE_TIME"
  • type=RECURRING, interval=MONTH, count=1"MONTHLY"
  • type=RECURRING, interval=MONTH, count=3"QUARTERLY"
  • type=RECURRING, interval=MONTH, count=6"BIANNUAL"
  • type=RECURRING, interval=MONTH, count=12"ANNUAL"
  • type=RECURRING, interval=YEAR, count=1"ANNUAL"
  • Other combinations → "{INTERVAL}_{COUNT}"

Example Request

curl -X POST "https://api.evon.com/api/sessions/550e8400-e29b-41d4-a716-446655440000/checkout" \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "priceIds": ["price_asdf98asdf98as98sdf"]
  }'

Example Request with Coupon

curl -X POST "https://api.evon.com/api/sessions/cbd94768-6af9-4094-90aa-00ec2f63b777/checkout" \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "priceIds": ["cmg4x57hx000qr9p7r294d0hb"],
    "couponCode": "JOIN120"
  }'

Response: The discount is automatically applied, reducing the price from $2820 to $2700.

Complete Session

Mark a session as completed after successful checkout.

POST /api/sessions/:session_id/complete

Path Parameters

ParameterTypeRequiredDescription
session_idstring (UUID)YesThe unique identifier of the session

Headers

HeaderRequiredDescription
X-API-KeyYesYour API key for authentication
Content-TypeYesMust be application/json

Request Body

{
  "paymentIntentId": "pi_1234567890",
  "metadata": {
    "orderNumber": "ORD-12345",
    "completionNotes": "Customer verified all information"
  }
}

Response

Status Code: 200 OK

{
  "success": true,
  "data": {
    "sessionId": "550e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "completedAt": "2025-01-15T11:00:00.000Z"
  }
}

Error Responses

Invalid Data (400)

Returned when required fields are missing or invalid.

{
  "error": "Datos inválidos",
  "details": [
    {
      "code": "invalid_type",
      "expected": "string",
      "received": "undefined",
      "path": ["sourceURL"],
      "message": "Required"
    }
  ]
}

Session Not Found (404)

{
  "error": "Session not found"
}

Session Already Completed (400)

{
  "success": false,
  "error": "Esta sesión ya fue completada"
}

Validation Failed (400)

When form answers don't match expected values:

{
  "error": "Validation failed",
  "validationErrors": [
    {
      "slug": "goal",
      "message": "Invalid option \"invalid_goal\". Must be one of the available options.",
      "availableOptions": ["weight_loss", "muscle_gain", "health_improvement"]
    }
  ]
}

Unauthorized (401)

{
  "error": "Invalid API key"
}

Internal Server Error (500)

{
  "success": false,
  "error": "Error interno del servidor"
}

Note: This error can occur during checkout or session completion operations if there are database connection issues or other server-side problems. The session data is preserved and can be retried.

Complete Workflow Example

Here's a complete example of using the Sessions API for a multi-step form with checkout:

// Step 1: Create session when user lands on form
const sessionResponse = await fetch('https://api.evon.com/api/sessions', {
  method: 'POST',
  headers: {
    'X-API-Key': 'your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    sourceURL: window.location.href,
    locale: 'EN_US',
    formTitle: 'Weight Management Consultation'
  })
});
 
const { data } = await sessionResponse.json();
const sessionId = data.sessionId;
 
// Step 2: Submit contact information
await fetch(`https://api.evon.com/api/sessions/${sessionId}`, {
  method: 'PUT',
  headers: {
    'X-API-Key': 'your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    contact: {
      email: 'john.doe@example.com',
      firstName: 'John',
      lastName: 'Doe',
      phone: '+1234567890'
    }
  })
});
 
// Step 3: Submit form answers
await fetch(`https://api.evon.com/api/sessions/${sessionId}`, {
  method: 'PUT',
  headers: {
    'X-API-Key': 'your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    answers: {
      weight: '185',
      height: '5\'10"',
      goal: 'weight_loss',
      medications: ['metformin'],
      mainMotivation: 'health',
      weightLossGoal: '20_30_lbs',
      commitmentLevel: 'very_committed'
    }
  })
});
 
// Step 4: Initiate checkout (optionally with a coupon)
const checkoutResponse = await fetch(
  `https://api.evon.com/api/sessions/${sessionId}/checkout`,
  {
    method: 'POST',
    headers: {
      'X-API-Key': 'your_api_key_here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      priceIds: ['price_asdf98asdf98as98sdf'],
      couponCode: 'SUMMER2025' // Optional: apply discount
    })
  }
);
 
const checkoutData = await checkoutResponse.json();
// checkoutData.checkout.finalAmount contains the discounted price
 
// Step 5: Process payment with Stripe (client-side)
// Use checkoutData.clientSecret with Stripe.js
 
// Step 6: Complete session after successful payment
await fetch(`https://api.evon.com/api/sessions/${sessionId}/complete`, {
  method: 'POST',
  headers: {
    'X-API-Key': 'your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    paymentIntentId: 'pi_1234567890'
  })
});

Notes

  • Sessions are scoped to your organization via the API key
  • Session IDs are UUIDs for security
  • Contact data creates or updates existing contacts based on email/phone
  • Form answers are validated against form question definitions
  • The checkout process integrates with Stripe for payment processing
  • Payment methods are always saved for future off-session charges
  • Coupon discounts are automatically calculated and applied to the payment amount
  • Sessions track the complete user journey from form start to payment completion
  • Answer validation ensures data integrity for select-type questions
  • The API supports multiple languages through the locale parameter