curl --request POST \
--url https://api.instaview.sk/runs/{id}/launch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"scheduledAt": "2026-09-15T09:00:00Z"
}
'import requests
url = "https://api.instaview.sk/runs/{id}/launch"
payload = { "scheduledAt": "2026-09-15T09:00:00Z" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({scheduledAt: '2026-09-15T09:00:00Z'})
};
fetch('https://api.instaview.sk/runs/{id}/launch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.instaview.sk/runs/{id}/launch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'scheduledAt' => '2026-09-15T09:00:00Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.instaview.sk/runs/{id}/launch"
payload := strings.NewReader("{\n \"scheduledAt\": \"2026-09-15T09:00:00Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.instaview.sk/runs/{id}/launch")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"scheduledAt\": \"2026-09-15T09:00:00Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.instaview.sk/runs/{id}/launch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"scheduledAt\": \"2026-09-15T09:00:00Z\"\n}"
response = http.request(request)
puts response.read_body{
"status": "RUNNING",
"affectedCalls": 42
}{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}{
"statusCode": 402,
"message": "Insufficient minutes available to schedule 10 interviews (50 minutes total). Please purchase additional minutes.",
"error": "PAYMENT_REQUIRED",
"billing": {
"billingSystem": "minutes",
"requiredMinutes": 50,
"availableMinutes": 12,
"requiredCredits": 50,
"availableCredits": 12,
"suggestedAction": "purchase_minutes"
},
"traceId": "4b1f0c9d2e6a47f8b3c5d7e9a1b2c3d4"
}{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}Launch Run
Fans the draft out into one conversation per contact and moves it DRAFT to RUNNING. Queued, not dialled: a 2xx means the conversations are on the dispatch queue, and each contact’s outcome arrives as a conversation.* webhook rather than in this response. All-or-nothing - the whole batch is admitted against billing first, and a run the company cannot afford is refused whole and stays a draft. Send scheduledAt to start it later instead, at most 30 days ahead: the run becomes SCHEDULED, dispatches nothing, and is admitted against billing again when it fires.
curl --request POST \
--url https://api.instaview.sk/runs/{id}/launch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"scheduledAt": "2026-09-15T09:00:00Z"
}
'import requests
url = "https://api.instaview.sk/runs/{id}/launch"
payload = { "scheduledAt": "2026-09-15T09:00:00Z" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({scheduledAt: '2026-09-15T09:00:00Z'})
};
fetch('https://api.instaview.sk/runs/{id}/launch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.instaview.sk/runs/{id}/launch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'scheduledAt' => '2026-09-15T09:00:00Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.instaview.sk/runs/{id}/launch"
payload := strings.NewReader("{\n \"scheduledAt\": \"2026-09-15T09:00:00Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.instaview.sk/runs/{id}/launch")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"scheduledAt\": \"2026-09-15T09:00:00Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.instaview.sk/runs/{id}/launch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"scheduledAt\": \"2026-09-15T09:00:00Z\"\n}"
response = http.request(request)
puts response.read_body{
"status": "RUNNING",
"affectedCalls": 42
}{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}{
"statusCode": 402,
"message": "Insufficient minutes available to schedule 10 interviews (50 minutes total). Please purchase additional minutes.",
"error": "PAYMENT_REQUIRED",
"billing": {
"billingSystem": "minutes",
"requiredMinutes": 50,
"availableMinutes": 12,
"requiredCredits": 50,
"availableCredits": 12,
"suggestedAction": "purchase_minutes"
},
"traceId": "4b1f0c9d2e6a47f8b3c5d7e9a1b2c3d4"
}{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}Starting it later
SendscheduledAt and the run is booked instead of dispatched. It moves to SCHEDULED, queues nothing, and starts on its own when the time arrives.
POST /runs/{id}/launch { "scheduledAt": "2026-09-15T09:00:00Z" }
{ "status": "SCHEDULED", "affectedCalls": 0 }
affectedCalls is 0 because nothing was queued. That is the honest count, not an omission.
Up to 30 days ahead — the same ceiling scheduleTime has always had on a single conversation, enforced by the same rule so one call and a batch of them cannot disagree about how far ahead you may plan. Further out, or not a valid ISO 8601 date-time, is a 400 and the run stays a DRAFT.
A scheduled run behaves like any other draft until it fires: attach more contacts, or cancel it to call the whole thing off. Cancelling clears the appointment, so a cancelled run never starts.
Contacts attached before the run fires are held, not dialled — Attach Contacts returns queued: 0 and they go out with everyone else at scheduledAt. A booked run has not started, so dispatching them on arrival would call those contacts days early.
What happens at the appointed time
The run is launched by exactly the code path an immediate launch takes — the same admission, the same fan-out — so a run that starts on Monday morning is indistinguishable from one somebody launched by hand on Monday morning. It may begin up to a minute late; a scheduled start is an appointment, not a deadline.SCHEDULED and is retried, with the reason in
scheduleError on Get Run. Topping up is enough to make it go;
there is nothing to re-book. Poll scheduleError, or a run you booked for a Monday can sit there
unstarted with nobody watching.Queued, not dialled
A2xx from this endpoint means the conversations exist and are on the dispatch queue. It does not mean anybody has been called.
The provider is called later by the dispatch worker, outside your request. So:
- per-contact outcomes do not come back in this response. They arrive as
conversation.*webhooks, and each payload carriesrunIdso you can attribute it to this run without a lookup - a
2xxis not a promise that every call connects. Contacts who never answer end upUNREACHABLE, which Get Run counts in its own bucket
{ "status": "RUNNING", "affectedCalls": 42 }
affectedCalls is how many conversations were queued, not how many calls were placed.
All of it, or none of it
The whole contact list is admitted against your billing before any of it is dispatched. A run you cannot afford in full is refused whole with a402, nothing is queued, and the run stays a DRAFT you can launch once you have topped up.
Partial admission — dialling as far as the balance goes — was deliberately rejected. It turns one request into an outcome nobody can predict or undo: you cannot un-call the contacts that already went out.
The 402 carries a billing object with what the batch needed and what was available, so you can size a smaller batch or work out the top-up.
Launching twice
DRAFT is the only status a run can be launched from, so a second launch is a 422 rather than a second fan-out — including when two launches arrive at the same instant. The run is locked for the duration, so concurrent launches cannot both pass the check.
A run with no contacts
422. There is nothing to dial, and a RUNNING run with no conversations would report a meaningless aggregate.
Error Scenarios
- 400 Bad Request:
scheduledAtis not a valid ISO 8601 date-time, or is more than 30 days ahead - 402 Payment Required: the company cannot afford the batch. Nothing dispatched, run stays a draft. A scheduled run is admitted at schedule time too, so an unaffordable run is refused before it is booked rather than at its start time
- 404 Not Found: the run does not exist, or belongs to another company
- 422 Unprocessable Entity: the run is not a draft, has no contacts, or its agent can no longer back a dispatch
- 403 Forbidden: the API key does not hold
write:runs
Related Resources
Get Run
Pause Run
Webhooks
Billing Errors
Authorizations
API key for authentication using Bearer scheme
Path Parameters
Query Parameters
Required for ATS API keys to specify which company to access. Ignored for standard company API keys.
Body
When the run should start dialling, ISO 8601, at most 30 days ahead. Omit it to start immediately. With it, the run becomes SCHEDULED and dispatches nothing until the time arrives.
"2026-09-15T09:00:00Z"
Response
Run launched, or scheduled to launch
The run's status after the transition
DRAFT, SCHEDULED, RUNNING, PAUSED, COMPLETED, CANCELLED "RUNNING"
How many of the run's calls this request moved: queued by a launch, withdrawn by a pause, restored by a resume, closed out by a cancel. Not calls placed - a 2xx means queued, not dialled.
42