API v2 · Jobs & webhooks

Long work runs in the background.

Live rates, batch rates and URL-based reconciliation answer 202 with a Job object, the same one GET /v2/jobs/{job_id} returns. Poll it using estimated_seconds to space the calls, or register a webhook and wait. Jobs are kept for 7 days. Both are free.

A finished job carries its result in result. Batch results can be large, so GET /v2/jobs/{job_id}/result streams them as NDJSON, one line per hotel and stay (vistalink jobs result); result_url is a download link when one exists.

Jobs

Get a job

GET/v2/jobs/{job_id}
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; any key with at least one scope can read its own jobs. Poll until status is succeeded, failed or canceled; jobs expire 7 days after creation.

Parameters

NameInTypeDescription
job_id
REQUIRED
pathstringThe job_id from a 202 response.

Example

Request
curl 'https://api.vistalink.com/v2/jobs/job_K8s2Lq9Wx4Np' \
  -H "Authorization: Bearer $VISTALINK_API_KEY"
Response
200
{
  "created_at": "2026-10-07T09:30:00Z",
  "estimated_seconds": 25,
  "job_id": "job_K8s2Lq9Wx4Np",
  "kind": "rates.live",
  "progress": {
    "done": 0,
    "total": 1
  },
  "status": "running",
  "updated_at": "2026-10-07T09:30:00Z"
}

Response 200

Successful Response

FieldTypeDescription
request_idstring | nullId of the request that returned this job; null in lists and webhook payloads.
job_id
REQUIRED
stringJob id, job_ plus 12 letters and digits.
kind
REQUIRED
stringrates.live (from POST /v2/rates or rates=refresh), rates.batch or rooms.reconcile. One of rates.live, rates.batch, rooms.reconcile.
status
REQUIRED
stringqueued, running, then succeeded, failed or canceled. One of queued, running, succeeded, failed, canceled.
progressobjectUnits of work done out of the total.
progress.doneintegerUnits of work finished. Default 0.
progress.totalintegerUnits of work in the job: hotels for rates.live, hotel and stay pairs for rates.batch, 1 for rooms.reconcile. Default 1.
created_at
REQUIRED
string (date-time)When the job was created, RFC 3339 UTC; jobs expire 7 days later.
updated_at
REQUIRED
string (date-time)When the job last changed, RFC 3339 UTC.
estimated_secondsinteger | nullRough time the job was expected to take when it was created, in seconds.
resultobject | nullThe outcome once succeeded: the POST /v2/rates response for rates.live, {summary, lines, format, warnings} for rates.batch, the reconcile result for rooms.reconcile. Null otherwise.
result_urlstring (uri) | nullrates.batch only: where to download the NDJSON result, a signed link or GET /v2/jobs/{job_id}/result; null for other kinds and until the job succeeds.
errorobject | nullWhy the job failed; null unless status is failed.
error.code
REQUIRED
stringError code, one of the API error codes, usually upstream_error, unavailable (the job stopped and its held credit was returned) or bad_request.
error.message
REQUIRED
stringExplanation in English.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
404not_foundThe hotel, offer, booking, job or webhook doesn't exist for this key.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Jobs

Download a job's result

GET/v2/jobs/{job_id}/result
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; any key with at least one scope. The NDJSON result of a rates.batch job, one line per hotel and stay, served here when the job's result_url points at this path.

Parameters

NameInTypeDescription
job_id
REQUIRED
pathstringThe job_id of a rates.batch job.

Example

Request
curl 'https://api.vistalink.com/v2/jobs/job_K8s2Lq9Wx4Np/result' \
  -H "Authorization: Bearer $VISTALINK_API_KEY"
Response
200
{"input":0,"hotel_id":"43d0be71-5f0e-4f1e-9a51-2b7b3c4d5e6f","stay":{"check_in":"2026-11-14","check_out":"2026-11-16"},"status":"observed","channel":"direct","engine":"SYNXIS","observed_at":"2026-10-07T09:30:00Z","rooms":[]}
{"input":1,"hotel_id":"43d0be71-5f0e-4f1e-9a51-2b7b3c4d5e6f","stay":{"check_in":"2026-11-21","check_out":"2026-11-23"},"status":"unknown","channel":"direct","rooms":[]}

Response 200

NDJSON lines

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
404not_foundThe hotel, offer, booking, job or webhook doesn't exist for this key.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Jobs

List jobs

GET/v2/jobs
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; any key with at least one scope. Newest first; pass next_cursor back as cursor for the next page.

Parameters

NameInTypeDescription
kindquerystringOnly jobs of this kind. One of rates.live, rates.batch, rooms.reconcile.
statusquerystringOnly jobs in this status. One of queued, running, succeeded, failed, canceled.
cursorqueryobjectThe next_cursor of the previous page; omit for the first page.
limitqueryintegerJobs per page.

Example

Request
curl 'https://api.vistalink.com/v2/jobs?cursor=MjAyNi0xMC0wN1QwOTozMDowMCswMDowMHxqb2JfSzhzMkxxOVd4NE5w' \
  -H "Authorization: Bearer $VISTALINK_API_KEY"
Response
200
{
  "jobs": [
    {
      "billing": {
        "amount": "0.04",
        "currency": "USD",
        "sku": "rates.direct.live",
        "units": 1
      },
      "created_at": "2026-10-07T09:30:00Z",
      "estimated_seconds": 25,
      "job_id": "job_K8s2Lq9Wx4Np",
      "kind": "rates.live",
      "progress": {
        "done": 1,
        "total": 1
      },
      "result": {
        "billing": {
          "amount": "0.002",
          "currency": "USD",
          "sku": "rates.direct.cached",
          "units": 1
        },
        "request_id": "req_8f2c1a9b3d4e5f60",
        "results": [
          {
            "channel": "direct",
            "engine": "SYNXIS",
            "hotel_id": "43d0be71-5f3c-4c8e-9a52-1d7e2b6f0a19",
            "input": 0,
            "observed_at": "2026-10-07T09:30:00Z",
            "rooms": [
              {
                "listing_key": "engine_room:1234567",
                "name": "Superior Room",
                "offers": [
                  {
                    "availability": "available",
                    "board": "breakfast",
                    "channel": "direct",
                    "currency": "EUR",
                    "engine": "SYNXIS",
                    "excluded_charges": [],
                    "free_cancellation": false,
                    "includes_taxes": true,
                    "listing_key": "engine_room:1234567",
                    "nightly_avg": "481.00",
                    "observed_at": "2026-10-07T09:30:00Z",
                    "occupancy": {
                      "adults": 2,
                      "children_ages": []
                    },
                    "offer_id": "off_t3c8e1a9b4f2d7e6a5c0b",
                    "rate_name": "Non-refundable, breakfast included",
                    "room_id": "5b1e2f3a-0c4d-4e5f-8a9b-1c2d3e4f5a6b",
                    "room_name": "Superior Room",
                    "total": "962.00",
                    "url": "https://umilta36.com/book?checkin=2026-11-14&checkout=2026-11-16"
                  }
                ],
                "room_id": "5b1e2f3a-0c4d-4e5f-8a9b-1c2d3e4f5a6b"
              }
            ],
            "status": "observed"
          }
        ],
        "summary": {
          "observed": 1,
          "stale": 0,
          "unknown": 0,
          "unresolved": 0,
          "unsupported": 0
        }
      },
      "status": "succeeded",
      "updated_at": "2026-10-07T09:30:00Z"
    }
  ],
  "request_id": "req_8f2c1a9b3d4e5f60"
}

Response 200

Successful Response

FieldTypeDescription
request_id
REQUIRED
stringOpaque id of this request, also sent as the X-Request-Id header; quote it when contacting support.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.
jobs
REQUIRED
Job[]Jobs on this page, newest first.
next_cursorstring | nullPass as cursor for the next page; null on the last page.

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Jobs

Cancel a job

POST/v2/jobs/{job_id}/cancel
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; needs the scope of the job's kind (rates for rates.*, reconcile for rooms.reconcile). Only queued or running jobs can be canceled (409 otherwise), and the credit held for the job is released.

Parameters

NameInTypeDescription
job_id
REQUIRED
pathstringThe job_id to cancel.

Example

Request
curl -X POST 'https://api.vistalink.com/v2/jobs/job_K8s2Lq9Wx4Np/cancel' \
  -H "Authorization: Bearer $VISTALINK_API_KEY"
Response
200
{
  "created_at": "2026-10-07T09:30:00Z",
  "estimated_seconds": 25,
  "job_id": "job_K8s2Lq9Wx4Np",
  "kind": "rates.live",
  "progress": {
    "done": 0,
    "total": 1
  },
  "status": "running",
  "updated_at": "2026-10-07T09:30:00Z"
}

Response 200

Successful Response

FieldTypeDescription
request_idstring | nullId of the request that returned this job; null in lists and webhook payloads.
job_id
REQUIRED
stringJob id, job_ plus 12 letters and digits.
kind
REQUIRED
stringrates.live (from POST /v2/rates or rates=refresh), rates.batch or rooms.reconcile. One of rates.live, rates.batch, rooms.reconcile.
status
REQUIRED
stringqueued, running, then succeeded, failed or canceled. One of queued, running, succeeded, failed, canceled.
progressobjectUnits of work done out of the total.
progress.doneintegerUnits of work finished. Default 0.
progress.totalintegerUnits of work in the job: hotels for rates.live, hotel and stay pairs for rates.batch, 1 for rooms.reconcile. Default 1.
created_at
REQUIRED
string (date-time)When the job was created, RFC 3339 UTC; jobs expire 7 days later.
updated_at
REQUIRED
string (date-time)When the job last changed, RFC 3339 UTC.
estimated_secondsinteger | nullRough time the job was expected to take when it was created, in seconds.
resultobject | nullThe outcome once succeeded: the POST /v2/rates response for rates.live, {summary, lines, format, warnings} for rates.batch, the reconcile result for rooms.reconcile. Null otherwise.
result_urlstring (uri) | nullrates.batch only: where to download the NDJSON result, a signed link or GET /v2/jobs/{job_id}/result; null for other kinds and until the job succeeds.
errorobject | nullWhy the job failed; null unless status is failed.
error.code
REQUIRED
stringError code, one of the API error codes, usually upstream_error, unavailable (the job stopped and its held credit was returned) or bad_request.
error.message
REQUIRED
stringExplanation in English.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
404not_foundThe hotel, offer, booking, job or webhook doesn't exist for this key.
409conflictThe Idempotency-Key was reused with a different body, or the resource is in a state that forbids the change.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Webhooks

List webhooks

GET/v2/webhooks
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; any key with at least one scope. The tenant's active webhooks, newest first; secrets are never returned again.

Example

Request
curl 'https://api.vistalink.com/v2/webhooks' \
  -H "Authorization: Bearer $VISTALINK_API_KEY"
Response
200
{
  "request_id": "req_8f2c1a9b3d4e5f60",
  "webhooks": [
    {
      "created_at": "2026-10-07T09:30:00Z",
      "events": [
        "rates.completed",
        "booking.updated"
      ],
      "is_active": true,
      "url": "https://partner.example/hooks/vistalink",
      "webhook_id": "wh_N4c7Bz1Qk2Vt"
    }
  ]
}

Response 200

Successful Response

FieldTypeDescription
request_id
REQUIRED
stringOpaque id of this request, also sent as the X-Request-Id header; quote it when contacting support.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.
webhooks
REQUIRED
Webhook[]Active webhooks, newest first.
webhooks[].webhook_id
REQUIRED
stringWebhook id, wh_ plus 12 letters and digits.
webhooks[].url
REQUIRED
string (uri)The https endpoint deliveries are POSTed to.
webhooks[].events
REQUIRED
string[]Events delivered to it. One of rates.completed, rates.batch.completed, rooms.reconcile.completed, booking.updated.
webhooks[].created_at
REQUIRED
string (date-time)When the webhook was created, RFC 3339 UTC.
webhooks[].is_activebooleanAlways true; deleted webhooks are not listed. Default true.

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Webhooks

Create a webhook

POST/v2/webhooks
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; each event needs its family's scope (booking.updated needs booking, rates.* need rates, rooms.reconcile.completed needs reconcile). Deliveries are signed POSTs described under Webhooks, retried after 1m, 5m, 30m, 2h, 12h and 24h; the secret is returned only in this response.

Request body

FieldTypeDescription
url
REQUIRED
string (uri)The https endpoint deliveries are POSTed to; it must resolve to a public address.
events
REQUIRED
string[]Events to deliver, each needing its family's scope on the key: booking.updated (booking), rates.completed and rates.batch.completed (rates), rooms.reconcile.completed (reconcile). At most 4. One of rates.completed, rates.batch.completed, rooms.reconcile.completed, booking.updated.
secretstring | nullYour own signing secret, 24 to 128 characters; one is generated when omitted.

Example

Request
curl -X POST 'https://api.vistalink.com/v2/webhooks' \
  -H "Authorization: Bearer $VISTALINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://partner.example/hooks/vistalink",
  "events": [
    "rates.completed",
    "booking.updated"
  ]
}'
Response
201
{
  "created_at": "2026-10-07T09:30:00Z",
  "events": [
    "rates.completed",
    "booking.updated"
  ],
  "request_id": "req_8f2c1a9b3d4e5f60",
  "secret": "whsec_3f9a0c2e7b5d4a1f8e6c9b2a7d4f1e0c",
  "url": "https://partner.example/hooks/vistalink",
  "webhook_id": "wh_N4c7Bz1Qk2Vt"
}

Response 201

Successful Response

FieldTypeDescription
request_id
REQUIRED
stringOpaque id of this request, also sent as the X-Request-Id header; quote it when contacting support.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.
webhook_id
REQUIRED
stringWebhook id, wh_ plus 12 letters and digits.
secret
REQUIRED
stringSigning secret for X-VistaLink-Signature, whsec_ plus hex when generated; shown only in this response.
url
REQUIRED
string (uri)The https endpoint deliveries are POSTed to.
events
REQUIRED
string[]Events delivered to it. One of rates.completed, rates.batch.completed, rooms.reconcile.completed, booking.updated.
created_at
REQUIRED
string (date-time)When the webhook was created, RFC 3339 UTC.

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
409conflictToo many webhooks.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Webhooks

Delete a webhook

DELETE/v2/webhooks/{webhook_id}
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; needs the scope of every event the webhook subscribes to. Answers 204 with no body, and deliveries still pending for it are dropped.

Parameters

NameInTypeDescription
webhook_id
REQUIRED
pathstringThe webhook_id returned when the webhook was created.

Example

Request
curl -X DELETE 'https://api.vistalink.com/v2/webhooks/wh_N4c7Bz1Qk2Vt' \
  -H "Authorization: Bearer $VISTALINK_API_KEY"
Response
204
// 204 No Content

Response 204

Successful Response

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
404not_foundThe hotel, offer, booking, job or webhook doesn't exist for this key.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Webhooks

List deliveries

GET/v2/webhooks/{webhook_id}/deliveries
Mode
Sync · 200
Price
Free
Auth
Any key

Synchronous and free; any key with at least one scope. Delivery attempts for one webhook, newest first, with the last HTTP status and error of each.

Parameters

NameInTypeDescription
webhook_id
REQUIRED
pathstringThe webhook_id whose deliveries to list.
cursorqueryobjectThe next_cursor of the previous page; omit for the first page.
limitqueryintegerDeliveries per page, newest first.

Example

Request
curl 'https://api.vistalink.com/v2/webhooks/wh_N4c7Bz1Qk2Vt/deliveries?cursor=MjAyNi0xMC0wN1QwOTozMDowMCswMDowMHx3aGRfUjJ0OE14NVFwMUx6' \
  -H "Authorization: Bearer $VISTALINK_API_KEY"
Response
200
{
  "deliveries": [
    {
      "attempts": 1,
      "created_at": "2026-10-07T09:30:00Z",
      "delivered_at": "2026-10-07T09:30:01Z",
      "delivery_id": "whd_R2t8Mx5Qp1Lz",
      "event": "booking.updated",
      "event_id": "evt_9Hd2Kq7Lm4Xp1Zr8",
      "last_status_code": 200,
      "status": "delivered"
    }
  ],
  "request_id": "req_8f2c1a9b3d4e5f60"
}

Response 200

Successful Response

FieldTypeDescription
request_id
REQUIRED
stringOpaque id of this request, also sent as the X-Request-Id header; quote it when contacting support.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.
deliveries
REQUIRED
WebhookDelivery[]Deliveries on this page, newest first.
deliveries[].delivery_id
REQUIRED
stringDelivery id, whd_ plus 12 letters and digits.
deliveries[].event
REQUIRED
stringThe event delivered. One of rates.completed, rates.batch.completed, rooms.reconcile.completed, booking.updated.
deliveries[].event_id
REQUIRED
stringId of the event, evt_ plus 16 letters and digits, the same for every webhook that receives it and sent as id in the payload.
deliveries[].status
REQUIRED
stringpending (waiting for its next attempt), delivered (your endpoint answered 2xx) or failed (all attempts used, or the webhook was deleted). One of pending, delivered, failed.
deliveries[].attempts
REQUIRED
integerAttempts made so far, at most 7.
deliveries[].last_status_codeinteger | nullHTTP status your endpoint gave on the last attempt; null when it could not be reached.
deliveries[].last_errorstring | nullWhy the last attempt failed, for example http_500 or webhook_deleted; null after success.
deliveries[].next_attempt_atstring (date-time) | nullWhen the next attempt is due, RFC 3339 UTC; null once delivered or failed.
deliveries[].created_at
REQUIRED
string (date-time)When the event was queued for this webhook, RFC 3339 UTC.
deliveries[].delivered_atstring (date-time) | nullWhen your endpoint accepted it, RFC 3339 UTC; null until then.
next_cursorstring | nullPass as cursor for the next page; null on the last page.

Errors

StatusCodeWhen
400bad_requestValidation errors carry details.fields[].
401unauthorizedNo key, or the key is unknown or revoked.
403forbiddenMissing scope.
404not_foundThe hotel, offer, booking, job or webhook doesn't exist for this key.
429rate_limitedOver the per-minute limit for the tier. Wait Retry-After seconds.
503unavailableWe're temporarily unable to serve the call. Retry with backoff.
Webhooks

Webhook events

Every delivery is a POST with the same envelope. See the WebhookEventPayload object below.

EventWhen
rates.completedA rates.live job finished. data is the Job.
rates.batch.completedA rates.batch job finished. data is the Job.
rooms.reconcile.completedA rooms.reconcile job finished. data is the Job.
booking.updatedEvery change to a booking's status or payment.status. data is the Booking.

WebhookEventPayload

The JSON body POSTed to your webhook URL, signed in X-VistaLink-Signature.

FieldTypeDescription
event
REQUIRED
stringThe event: rates.completed, rates.batch.completed or rooms.reconcile.completed when a job finishes (succeeded or failed), booking.updated when a booking's status or payment status changes. One of rates.completed, rates.batch.completed, rooms.reconcile.completed, booking.updated.
id
REQUIRED
stringEvent id, evt_ plus 16 characters; use it to discard repeats, since a retried delivery carries the same id.
created_at
REQUIRED
string (date-time)When the event happened, RFC 3339 UTC.
data
REQUIRED
objectThe Job for job events, the Booking for booking.updated.
Jobs & webhooks

Verifying signatures

Each delivery carries X-VistaLink-Signature: t=<unix>,v1=<hex>. v1 is the HMAC-SHA256 of <t>.<raw body> with your secret. Compare in constant time and reject old timestamps.

Any 2xx acknowledges a delivery. Anything else is retried after 1m, 5m, 30m, 2h, 12h, 24h. The event id is stable across retries, so dedupe on it.

Creating a webhook answers 201 with the whole webhook and its secret, shown only then. Webhooks carry is_active. List a webhook's deliveries to see each one's status (pending, delivered or failed), its attempts, your endpoint's last_status_code and last_error, and next_attempt_at while it's still pending.

TypeScript
import { createHmac, timingSafeEqual } from "node:crypto";

// header: "t=1791364462,v1=5f2c…"; body: the raw request body string
export function verify(header: string, body: string, secret: string): boolean {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${body}`)
    .digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 ?? "");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && a.length === b.length && timingSafeEqual(a, b);
}
Objects

Shared objects.

Objects that appear in more than one place. Billing is on the Billing page and ErrorBody under Errors & limits.

Job

Background work started by a 202 response. Also the data of the *.completed webhooks.

FieldTypeDescription
request_idstring | nullId of the request that returned this job; null in lists and webhook payloads.
job_id
REQUIRED
stringJob id, job_ plus 12 letters and digits.
kind
REQUIRED
stringrates.live (from POST /v2/rates or rates=refresh), rates.batch or rooms.reconcile. One of rates.live, rates.batch, rooms.reconcile.
status
REQUIRED
stringqueued, running, then succeeded, failed or canceled. One of queued, running, succeeded, failed, canceled.
progressobjectUnits of work done out of the total.
progress.doneintegerUnits of work finished. Default 0.
progress.totalintegerUnits of work in the job: hotels for rates.live, hotel and stay pairs for rates.batch, 1 for rooms.reconcile. Default 1.
created_at
REQUIRED
string (date-time)When the job was created, RFC 3339 UTC; jobs expire 7 days later.
updated_at
REQUIRED
string (date-time)When the job last changed, RFC 3339 UTC.
estimated_secondsinteger | nullRough time the job was expected to take when it was created, in seconds.
resultobject | nullThe outcome once succeeded: the POST /v2/rates response for rates.live, {summary, lines, format, warnings} for rates.batch, the reconcile result for rooms.reconcile. Null otherwise.
result_urlstring (uri) | nullrates.batch only: where to download the NDJSON result, a signed link or GET /v2/jobs/{job_id}/result; null for other kinds and until the job succeeds.
errorobject | nullWhy the job failed; null unless status is failed.
error.code
REQUIRED
stringError code, one of the API error codes, usually upstream_error, unavailable (the job stopped and its held credit was returned) or bad_request.
error.message
REQUIRED
stringExplanation in English.
billingBilling | nullWhat a billed call cost. Present on every billed response; billing is null on free ones.