Save sales readiness answers

Create or update the go-live readiness answers for one or more steps of one agent type at one rooftop. Spyne stores them as a questionnaire. Nothing else is triggered: no backend reads these answers, and they do not gate go-live.

POSThttps://api.spyne.ai/central-config/v1/vini-config/go-live-readiness
AuthBearer token (console user)Rate limitNot documentedProcessingSynchronous; one read and one write of the config, plus a change-log entry
📌

Sales agents: send entity: sales_inbound with the steps afterHours, officeHoursOverflow and officeHoursAllLeads, or entity: sales_outbound with runFirstCampaign only.

Auth: Bearer token of a signed-in user · Rate limit: not documented · Processing: synchronous, one read and one write of the config, plus a change-log entry

Before you call it

  • You need enterpriseId, teamId and the agent type (entity). entity must be one of the seven values listed on Get readiness answers.
  • Send at least one step. Each entry needs a non-empty question.
  • The body is deep-merged into the rooftop's config for that agent type. Each step you send replaces that step's whole array. Steps you leave out are kept. Sending null for a step clears it. Agent records stored in the same config are not touched.
  • Because a step is replaced as a whole, send every entry you want to keep for that step, not only the changed one.
  • If the rooftop has no config for this agent type yet, one is created. Every write is recorded in the config change log.
  • The token's user ID is recorded. The route does not check that the token belongs to the enterpriseId or teamId in the body.

Step keys the onboarding console writes, by agent type:

entityStep keyQuestions (label saved in question)
sales_inboundafterHours"Calls during after hours", "Speed to Lead on after hour leads", "Followup on after hour leads", "Appointment Reminder"
sales_inboundofficeHoursOverflow"Overflow Calls", "Speed to lead", "Followup", "Appointment Reminder"
sales_inboundofficeHoursAllLeads"Handle all office-hours leads"
sales_outboundrunFirstCampaign"First campaign started"
service_inboundafterHours"Calls during after hours" only
service_inboundofficeHoursOverflow"Overflow Calls" only
service_outboundrunFirstCampaign"First campaign started"
acquisition_outboundrunFirstCampaign"First campaign started"
anyviniCallTranscriptsRecordingsWritten after a call transcript or recording upload. question is transcript or recordings; answer is an array of file URLs.

The backend accepts any step key. Only afterHours is marked as agreed with the backend in the console code. The other key names are to be confirmed.


Request body

Requiredalways sendOptionalcan be left out
Request checklist
  1. Headers: set Authorization: Bearer YOUR_TOKEN and Content-Type: application/json.
  2. Identify the rooftop and agent type: send enterpriseId, teamId and entity.
  3. Add the answers: build onboardingGoLiveReadiness with one key per step you are saving.
  4. Send it and check for 200.
ParameterTypeRequiredDescription
enterpriseIdstringRequiredDealer group ID. Must not be empty.
teamIdstringRequiredRooftop ID. Must not be empty.
entitystringRequiredAgent type. One of the seven allowed values.
enterpriseNamestringOptionalStored on the config if sent.
teamNamestringOptionalStored on the config if sent.
onboardingGoLiveReadinessobjectRequiredMap of step name to an array of entries, or to null to clear the step. Must contain at least one key.
<step>array or nullRequiredOne key per step, for example afterHours.
questionstringRequiredQuestion text. Must not be empty. The console stores the human label here, not a key.
answeranyRequiredAny JSON value. The key must be present. Toggle steps use a boolean.
commentstringOptionalExtra fields are kept as sent. The console sends comment: the reason when a toggle is off, or an empty string when on.

Sample request

curl -X POST "https://api.spyne.ai/central-config/v1/vini-config/go-live-readiness" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enterpriseId": "<enterpriseId>",
    "teamId": "<teamId>",
    "entity": "sales_inbound",
    "onboardingGoLiveReadiness": {
      "afterHours": [
        { "question": "Calls during after hours", "answer": true, "comment": "" },
        { "question": "Speed to Lead on after hour leads", "answer": true, "comment": "" },
        { "question": "Followup on after hour leads", "answer": false, "comment": "BDC covers this" },
        { "question": "Appointment Reminder", "answer": true, "comment": "" }
      ]
    }
  }'
import requests

res = requests.post(
    "https://api.spyne.ai/central-config/v1/vini-config/go-live-readiness",
    headers={"Authorization": "Bearer YOUR_TOKEN"},
    json={
        "enterpriseId": "<enterpriseId>",
        "teamId": "<teamId>",
        "entity": "sales_outbound",
        "onboardingGoLiveReadiness": {
            "runFirstCampaign": [
                {"question": "First campaign started", "answer": True, "comment": ""}
            ]
        },
    },
)
print(res.status_code, res.json())
const res = await fetch(
  'https://api.spyne.ai/central-config/v1/vini-config/go-live-readiness',
  {
    method: 'POST',
    headers: {
      Authorization: 'Bearer YOUR_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      enterpriseId: '<enterpriseId>',
      teamId: '<teamId>',
      entity: 'service_inbound',
      onboardingGoLiveReadiness: {
        viniCallTranscriptsRecordings: [
          { question: 'transcript', answer: ['<fileUrl>'] },
        ],
      },
    }),
  }
);
console.log(res.status, await res.json());

Sample response

The response is the whole saved config for this rooftop and agent type. That includes any agent records stored under their agent ID, not only the readiness map.

{
  "_id": "<configId>",
  "enterpriseId": "<enterpriseId>",
  "teamId": "<teamId>",
  "enterpriseName": "<enterpriseName>",
  "teamName": "<teamName>",
  "userId": "<userId>",
  "domain": "product",
  "type": "single",
  "entity": "sales_inbound",
  "entityconfig": {
    "<agentId>": { "agentId": "<agentId>", "agentName": "<agentName>", "isOnboarded": false },
    "onboardingGoLiveReadiness": {
      "afterHours": [
        { "question": "Calls during after hours", "answer": true, "comment": "" }
      ]
    }
  },
  "createdAt": "2026-10-01T15:04:05.000Z",
  "updatedAt": "2026-10-12T15:04:05.000Z",
  "__v": 0
}
{
  "success": false,
  "message": "Validation error",
  "errors": [
    {
      "code": "custom",
      "message": "onboardingGoLiveReadiness must include at least one step",
      "path": ["onboardingGoLiveReadiness"]
    }
  ]
}
{
  "status": "401",
  "message": "Invalid Auth key"
}
{
  "success": false,
  "message": "Failed to save Go-Live readiness",
  "error": "<error message>"
}

Response parameters (200)

ParameterTypeDescription
_idstringConfig ID.
enterpriseIdstringDealer group ID.
teamIdstringRooftop ID.
enterpriseNamestringStored dealer group name, if any.
teamNamestringStored rooftop name, if any.
userIdstringUser who made the last write, taken from the token.
domainstringAlways product.
typestringAlways single.
entitystringAgent type.
entityconfigobjectThe full stored config: agent records keyed by agent ID, plus onboardingGoLiveReadiness.
onboardingGoLiveReadinessobjectReadiness map after the merge.
createdAtstringISO timestamp.
updatedAtstringISO timestamp.
__vnumberDocument version.

Errors

StatusCodeWhen it happens
400Validation errorA required field is missing or empty, entity is not allowed, onboardingGoLiveReadiness is empty, a step is not an array or null, or an entry has an empty question.
401Invalid Auth keyNo Authorization: Bearer header, or the user service rejects the token.
401User ID not found in tokenThe token validated but carried no user ID.
500Failed to save Go-Live readinessUnexpected error during the write.

What happens next

Nothing else runs. The answers sit in the config as a record of what the dealer said.

In the onboarding console, each save is paired with a call that marks the matching checklist task done or in progress, for example After Hours. That call is Mark a task done and runs in parallel with this one. If one call fails, the other is not rolled back. Saving every toggle as off with a comment still counts as a completed task.

To switch the agent live, call Put an agent live. Readiness is not checked there.


Did this page help you?