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/sessionsHeaders
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key for authentication |
Content-Type | Yes | Must 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
| Parameter | Type | Required | Description |
|---|---|---|---|
formId | string (UUID) | No | Existing form ID to use as template |
formTitle | string | No | Form title (default: "Weight Management") |
formDescription | string | No | Form description (default: "TrimRx Weight Management Form") |
locale | enum | No | Language code: EN_US, ES_ES, ES_MX, FR_FR, DE_DE, IT_IT, PT_BR, RU_RU, ZH_CN, JA_JP (default: "EN_US") |
sourceURL | string | Yes | URL where session originated |
clientIp | string | No | Client IP address for tracking |
userAgent | string | No | Browser user agent |
everflowTrackingId | string | No | Everflow tracking identifier |
standardTimezone | string | No | Standard timezone name |
timezone | string | No | Timezone 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_idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | Yes | The unique identifier of the session |
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key for authentication |
Content-Type | Yes | Must 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_idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | Yes | The unique identifier of the session |
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key for authentication |
Content-Type | Yes | Must 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
| Parameter | Type | Required | Description |
|---|---|---|---|
contact | object | No | Contact information |
contact.email | string | No | Contact email address |
contact.firstName | string | No | Contact first name |
contact.lastName | string | No | Contact last name |
contact.phone | string | No | Contact phone number |
answers | object | No | Form answers as key-value pairs where values can be string, number, boolean, or array of strings |
metadata | object | No | Additional metadata to store with the submission |
attributions | object | No | Attribution 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_idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | Yes | The unique identifier of the session |
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key for authentication |
Content-Type | Yes | Must 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/checkoutPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | Yes | The unique identifier of the session |
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key for authentication |
Content-Type | Yes | Must be application/json |
Request Body
{
"priceIds": ["price_asdf98asdf98as98sdf", "price_jgh09erg9f89fd9d"],
"couponCode": "SUMMER2025"
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
priceIds | array | Yes | Array of price IDs (at least one required) |
couponCode | string | No | Stripe 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
| Field | Type | Description |
|---|---|---|
checkout.originalAmount | number | Original total amount before discount |
checkout.finalAmount | number | Final amount after applying coupon discount |
checkout.amount | number | Same as finalAmount (for compatibility) |
checkout.coupon | object | Coupon details (only present if valid coupon was applied) |
checkout.coupon.code | string | The coupon code that was applied |
checkout.coupon.percentOff | number | Percentage discount (if applicable) |
checkout.coupon.amountOff | number | Fixed amount discount (if applicable) |
checkout.coupon.discountAmount | number | Actual 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
couponobject 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/completePath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | Yes | The unique identifier of the session |
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key for authentication |
Content-Type | Yes | Must 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
Related Endpoints
- Products API - Manage products and prices
- Stripe Integration - Direct Stripe payment processing
- Forms API - Manage form templates and questions
- API Authentication - Learn about API keys