Skip to main content
This guide walks through the complete lifecycle of a customer on the Voice Agents platform — from initial onboarding to receiving real-time call events via your callback URL.

Lifecycle Overview


Step 1 — Onboard a Brand

Register your brand (Shopify store) to create a workspace with billing configuration. All subsequent API operations are scoped to this workspace.
POST /v2/workspace/onboard/shopify

Authentication

HeaderDescription
x-public-keyYour public API key
x-private-keyYour private API key

Body Parameters

ParameterTypeRequiredDescription
namestringYesYour store/brand name
currencyCodestringYesStore currency (e.g., INR, USD)
timezonestringYesStore timezone (e.g., Asia/Kolkata)
supportContacts.phoneNumberstringYesSupport phone number in E.164 format
supportContacts.emailstringNoSupport email address
trustSignals.valuePropositionOneLinerstringYesOne-line brand value proposition
trustSignals.customersTillDateintegerNoTotal customers served
trustSignals.totalOrdersFulfilledintegerNoTotal orders fulfilled
trustSignals.storeRatingnumberNoStore rating (e.g., 4.8)
policyFramework.returnPolicyobjectNoReturn window, processing fee, refund timeline
policyFramework.shippingPolicyobjectNoDelivery timeline, free shipping threshold
policyFramework.codPolicyobjectNoCOD availability and additional fee
curl --location 'https://api.voice-agents.miraiminds.co/v2/workspace/onboard/shopify' \
--header 'x-public-key: pk_your_public_key' \
--header 'x-private-key: sk_your_private_key' \
--header 'Content-Type: application/json' \
--data '{
    "name": "Acme Store",
    "currencyCode": "INR",
    "timezone": "Asia/Kolkata",
    "supportContacts": {
        "phoneNumber": "+919876543210",
        "email": "support@acme.com"
    },
    "trustSignals": {
        "valuePropositionOneLiner": "Handcrafted products using sustainable materials",
        "customersTillDate": 15000,
        "totalOrdersFulfilled": 42000,
        "storeRating": 4.8
    },
    "policyFramework": {
        "returnPolicy": {
            "windowDays": 7,
            "processingFee": { "amount": 50 },
            "refundTimelineDays": 3
        },
        "shippingPolicy": {
            "deliveryTimeline": { "minDays": 3, "maxDays": 5 },
            "freeShippingMinOrderValue": 999
        },
        "codPolicy": {
            "enabled": true,
            "additionalFee": { "amount": 50 }
        }
    }
}'
Success Response (200 OK)
{
  "success": true,
  "data": {
    "workspace": "68d63c242cd956c2bb41cd3a",
    "status": "active"
  }
}
Save your workspace ID — it is required as a header in every subsequent API call.

Step 2 — Create an AI Agent

Create a voice assistant configured with a persona, language, voice, call settings, and optionally a knowledge base.
POST /v1/admin/assistant/create

Headers

HeaderRequiredDescription
x-public-keyYesYour public API key
x-private-keyYesYour private API key
workspaceYesYour workspace ID

Body Parameters

ParameterTypeRequiredDescription
namestringYesAssistant display name (max 40 chars)
variant.typestringYesAssistant type: abandoned_cart or custom
variant.config.systemPromptstringNoCustom system prompt (for custom variant)
agent.identity.namestringYesAgent’s spoken name (e.g., Priya)
agent.identity.genderstringYesmale or female
agent.identity.voicestringYesVoice identifier (see Voice Gallery)
icpContext.languagestringYesCall language: hinglish, english, hindi, tamil, telugu, and more
icpContext.targetAgeGroupsarrayNogen_z, millennials, gen_x, boomers
icpContext.locationTiersarrayNometro_urban, tier1, tier2, tier3, rural
callSettings.slotsarrayNoTime windows when calls can be made (e.g., 10:0017:30)
callSettings.maxCallDurationnumberNoMaximum call duration in seconds
callSettings.concurrentCallCountnumberNoMax concurrent calls (up to 10)
callSettings.retryProtocolobjectNoRetry behavior for no-pick-up and low-engagement calls
analysisPlanobjectNoSuccess criteria and summary instructions for post-call AI analysis
knowledgeBase.faqarrayNoFAQ pairs (question + answer)
knowledgeBase.documentsarrayNoExternal documents by URL (pdf, txt, docx, markdown)
curl --location 'https://api.voice-agents.miraiminds.co/v1/admin/assistant/create' \
--header 'x-public-key: pk_your_public_key' \
--header 'x-private-key: sk_your_private_key' \
--header 'workspace: 68d63c242cd956c2bb41cd3a' \
--header 'Content-Type: application/json' \
--data '{
    "name": "Acme Abandoned Cart Agent",
    "variant": {
        "type": "abandoned_cart"
    },
    "agent": {
        "identity": {
            "name": "Priya",
            "gender": "female",
            "voice": "priya"
        }
    },
    "icpContext": {
        "language": "hinglish",
        "targetAgeGroups": ["millennials", "gen_z"],
        "locationTiers": ["metro_urban", "tier1"]
    },
    "callSettings": {
        "slots": [
            { "startTime": "10:00", "endTime": "13:00" },
            { "startTime": "15:00", "endTime": "19:00" }
        ],
        "maxCallDuration": 180,
        "concurrentCallCount": 5,
        "retryProtocol": {
            "maxAttemptsNoPickup": 2,
            "maxAttemptsLowEngagement": 1,
            "reAttemptPeriod": 300,
            "maxRescheduleCount": 1
        }
    },
    "analysisPlan": {
        "successCriteriaPlan": "Call is successful if the customer confirmed intent to complete the purchase or provided a reason for abandonment.",
        "summaryPlan": "Summarize customer sentiment and whether they intend to buy."
    },
    "knowledgeBase": {
        "faq": [
            {
                "question": "What is your return policy?",
                "answer": "We offer 7-day returns with a ₹50 processing fee."
            }
        ]
    }
}'
Success Response (200 OK)
{
  "success": true,
  "data": {
    "assistantId": "6927ec5c9322ed9f9fb55c68"
  }
}
Save the assistantId — it is required when initiating calls.
variant.type is immutable after creation. Choose abandoned_cart for cart recovery flows or custom for fully flexible prompts.

Step 3 — Initiate a Call

Trigger an outbound call to a customer using the assistant you created.
POST /v2/call/initiate

Headers

HeaderRequiredDescription
x-public-keyYesYour public API key
x-private-keyYesYour private API key
workspaceYesYour workspace ID

Body Parameters

ParameterTypeRequiredDescription
phoneNumberstringYesCustomer’s phone number in E.164 format (e.g., +919876543210)
assistantstringYesThe assistantId from Step 2
callbackUrlstringYesHTTPS URL to receive webhook events for this call
prioritybooleanNoSet true to jump the call queue
payloadobjectNoCall context data (customer info, cart items, pricing) passed to the AI during the call
metadataobjectNoArbitrary key-value pairs echoed back in every webhook event
metadata.discountobjectNoDiscount code to offer during the call (code, value, codeType, applyAs)

payload Object

The payload provides the AI with context about the customer and their cart. All fields are optional but recommended for abandoned_cart assistants.
FieldTypeDescription
customer.firstNamestringCustomer’s first name
customer.lastNamestringCustomer’s last name
customer.emailstringCustomer’s email
customer.phonestringCustomer’s phone
lineItemsarrayCart items — each with title, quantity, and variant.id + variant.title
subtotalPriceSet.shopMoney.amountstringCart subtotal
totalPriceSet.shopMoney.amountstringCart total
abandonedCheckoutUrlstringDirect URL to the abandoned checkout
shippingAddressobjectCustomer’s shipping address
curl --location 'https://api.voice-agents.miraiminds.co/v2/call/initiate' \
--header 'x-public-key: pk_your_public_key' \
--header 'x-private-key: sk_your_private_key' \
--header 'workspace: 68d63c242cd956c2bb41cd3a' \
--header 'Content-Type: application/json' \
--data '{
    "phoneNumber": "+919876543210",
    "assistant": "6927ec5c9322ed9f9fb55c68",
    "callbackUrl": "https://your-app.com/webhooks/voice-agent",
    "priority": false,
    "payload": {
        "id": "gid://shopify/AbandonedCheckout/66509168181329",
        "abandonedCheckoutUrl": "https://acme.com/checkout/recover?token=abc123",
        "customer": {
            "firstName": "Riya",
            "lastName": "Shah",
            "email": "riya@example.com",
            "phone": "+919876543210"
        },
        "lineItems": [
            {
                "title": "Handcrafted Tote Bag",
                "quantity": 1,
                "variant": {
                    "id": "gid://shopify/ProductVariant/44001234567",
                    "title": "Brown / Medium"
                }
            }
        ],
        "subtotalPriceSet": { "shopMoney": { "amount": "1895.0" } },
        "totalPriceSet": { "shopMoney": { "amount": "1945.0" } },
        "shippingAddress": {
            "city": "Mumbai",
            "province": "Maharashtra",
            "country": "India",
            "zip": "400001"
        }
    },
    "metadata": {
        "orderId": "ORD-9876",
        "customerId": "cust_001",
        "discount": {
            "code": "SAVE10",
            "description": "10% off your cart",
            "value": 10,
            "codeType": "percentage",
            "applyAs": "additional"
        }
    }
}'
Success Response (200 OK)
{
  "success": true,
  "data": {
    "callId": "c_550e8400-e29b-41d4-a716-446655440000",
    "status": "queued"
  }
}
The call is placed asynchronously. The callId is returned immediately — real-time status updates are delivered to your callbackUrl.

Step 4 — Abort a Call

Cancel a queued or in-progress call using the callId returned during initiation.
POST /v2/call/abort

Body Parameters

ParameterTypeRequiredDescription
callIdstringYesThe callId returned when the call was initiated
curl --location 'https://api.voice-agents.miraiminds.co/v2/call/abort' \
--header 'x-public-key: pk_your_public_key' \
--header 'x-private-key: sk_your_private_key' \
--header 'workspace: 68d63c242cd956c2bb41cd3a' \
--header 'Content-Type: application/json' \
--data '{
    "callId": "c_550e8400-e29b-41d4-a716-446655440000"
}'
Success Response (200 OK)
{
  "success": true,
  "message": "Call aborted successfully",
  "data": {
    "callId": "c_550e8400-e29b-41d4-a716-446655440000",
    "status": "aborted"
  }
}
After a successful abort, your callbackUrl will receive a call.aborted event.
Calls that have already reached call.completed or call.lifecycle-ended state cannot be aborted.

Step 5 — Handle Callback URL & Lifecycle Events

The callbackUrl you provided when initiating the call receives real-time webhook events as the call progresses. Your custom metadata is echoed back in every event so you can correlate events to your internal records.

Call Lifecycle

Lifecycle Events Reference

EventTrigger
call.initiateCall has been queued and is dialing
call.in-progressCustomer answered — AI conversation started
call.endedPhone connection dropped
call.completedRecording, transcript, and duration are ready
call.timeoutCall exceeded maximum allowed duration
end-of-callAI analysis complete — summary and structured data available
call.lifecycle-endedFinal event — all processing finished
call.failedCall could not connect
call.busyCustomer’s line was busy
call.no-answerCustomer did not pick up
call.abortedCall was cancelled via the abort API
call.rescheduledRetry scheduled for a later time

Webhook Payload Structure

Every event uses the same envelope with your metadata echoed back:
{
  "metadata": {
    "customerId": "cust_001",
    "orderId": "ORD-9876"
  },
  "event": {
    "type": "call.completed",
    "data": {
      "call": {
        "id": "c_550e8400-e29b-41d4-a716-446655440000",
        "status": "completed",
        "startedAt": "2025-11-27T10:00:00Z",
        "endedAt": "2025-11-27T10:02:30Z",
        "durationSeconds": 150,
        "recordingUrl": "https://api.voice-agents.miraiminds.co/recordings/...",
        "detailUrl": "https://api.voice-agents.miraiminds.co/calls/..."
      }
    }
  }
}
The end-of-call event additionally includes AI analysis and credit usage:
{
  "event": {
    "type": "end-of-call",
    "data": {
      "analysis": {
        "success": true,
        "summary": "Customer confirmed intent to complete the purchase after receiving the discount code.",
        "insights": {
          "sentiment": "positive",
          "intent": "purchase_confirmed"
        }
      },
      "credits": {
        "used": 2.5,
        "available": 105.0
      }
    }
  }
}

Handling Webhooks — Example

app.post('/webhooks/voice-agent', (req, res) => {
  // Always respond immediately — do not wait for processing
  res.status(200).send('OK');

  const { event, metadata } = req.body;
  console.log(`[${event.type}] customer=${metadata.customerId}`);

  switch (event.type) {
    case 'call.initiate':
      updateCallStatus(metadata.customerId, 'dialing');
      break;

    case 'call.in-progress':
      updateCallStatus(metadata.customerId, 'in-progress');
      break;

    case 'call.aborted':
      updateCallStatus(metadata.customerId, 'aborted');
      break;

    case 'call.failed':
    case 'call.busy':
    case 'call.no-answer':
      logCallFailure(metadata.customerId, event.type);
      break;

    case 'call.completed':
      saveRecording(event.data.call.id, event.data.call.recordingUrl);
      break;

    case 'end-of-call':
      saveAnalysis(metadata.customerId, event.data.analysis);
      deductCredits(event.data.credits.used);
      break;

    case 'call.lifecycle-ended':
      closeCallRecord(metadata.customerId);
      break;

    default:
      console.log('Unhandled event:', event.type);
  }
});

Callback URL Tips

  • HTTPS required — plain HTTP endpoints are rejected.
  • Respond with 200 OK immediately — Voice Agents does not wait for your processing; slow responses may trigger retries.
  • Use metadata for correlation — pass your internal IDs (e.g., customerId, orderId) when initiating the call; they are echoed in every event.
  • Verify signatures — validate the webhook signature on every incoming request. See Webhook Signature Verification.

API Summary

StepMethodEndpointPurpose
OnboardPOST/v2/workspace/onboard/shopifyRegister a brand and create a workspace
Create AgentPOST/v1/admin/assistant/createCreate a voice assistant
Initiate CallPOST/v2/call/initiateTrigger an outbound call
Abort CallPOST/v2/call/abortCancel a queued or active call
Receive Eventsyour callbackUrlHandle real-time call lifecycle events