Skip to main content

Overview

Vine turns a business URL into structured data through two endpoints:
  1. Detect (POST /api/v1/detect) — synchronous. Send a URL, get back the providers Vine detected and the proposed connections behind them in ~25 seconds.
  2. Extract (POST /api/v1/extract) — async. Send a URL, Vine detects providers and pulls data from each, and you poll until the job reaches a terminal state.
Every request is authenticated with a Bearer API key. detect returns its result directly; extract returns a job you poll with GET /api/v1/extractions/{id}.
1

Get an API key

Mint a key with the key-management endpoint. The plaintext is returned once — store it immediately; it is never recoverable.
cURL
curl -X POST https://vine.getcourtyard.ai/api/v1/keys \
  -H "Content-Type: application/json" \
  -d '{ "name": "my-first-key", "env": "test" }'
Response
{
  "key": {
    "id": "clz…",
    "name": "my-first-key",
    "keyPrefix": "vine_test_Ab",
    "plaintext": "vine_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "scopes": ["detect", "extract", "extractions:read"],
    "rateTier": "internal",
    "createdAt": "2026-06-25T18:00:00.000Z"
  }
}
Keys look like vine_test_… (sandbox, the default) or vine_live_… (production). Attach yours as a Bearer token on every request:
Authorization: Bearer vine_test_xxxxxxxxxxxxxxxx
Keep keys server-side. The default scopes — detect, extract, extractions:read — cover the whole flow below.
2

Detect providers (synchronous)

Send the business URL. detect blocks until the classifier finishes (~25s) and returns the result directly — no polling.
curl -X POST https://vine.getcourtyard.ai/api/v1/detect \
  -H "Authorization: Bearer $VINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://www.mindbodyonline.com/explore/locations/thesharpbarber" }'
A 200 OK returns the detected providers and the connections you can feed into an extraction:
{
  "schemaVersion": "extraction.v1",
  "url": "https://www.mindbodyonline.com/explore/locations/thesharpbarber",
  "providers": ["mindbody"],
  "connections": [
    {
      "provider": "mindbody",
      "actionType": "book",
      "actionUrl": "https://widgets.mindbodyonline.com/...",
      "providerParams": { "siteId": "-99" }
    }
  ],
  "durationMs": 24650
}
3

Extract provider data (async)

To pull live data (schedules, menus, practitioners, availability), submit an extraction. An Idempotency-Key is optional — supply one to make a submit safely retryable; omit it and each call creates a new job.
curl -X POST https://vine.getcourtyard.ai/api/v1/extract \
  -H "Authorization: Bearer $VINE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-key-001" \
  -d '{ "url": "https://www.mindbodyonline.com/explore/locations/thesharpbarber" }'
The API responds with 202 Accepted and a job envelope:
{
  "schemaVersion": "extraction.v1",
  "id": "ext_01JX4MQTCPB9NZ7KXHVF3A2R8",
  "kind": "extract",
  "status": "queued",
  "pollUrl": "https://vine.getcourtyard.ai/api/v1/extractions/ext_01JX4MQTCPB9NZ7KXHVF3A2R8",
  "createdAt": "2026-06-25T18:00:00.000Z",
  "retryAfterSeconds": 4
}
4

Poll until terminal

Poll pollUrl (or GET /api/v1/extractions/{id}) until status is no longer queued or running. An extraction is readable only by the key that created it.
curl https://vine.getcourtyard.ai/api/v1/extractions/ext_01JX4MQTCPB9NZ7KXHVF3A2R8 \
  -H "Authorization: Bearer $VINE_API_KEY"
A succeeded job carries the extracted data in result:
{
  "schemaVersion": "extraction.v1",
  "id": "ext_01JX4MQTCPB9NZ7KXHVF3A2R8",
  "kind": "extract",
  "status": "succeeded",
  "attempt": 1,
  "createdAt": "2026-06-25T18:00:00.000Z",
  "startedAt": "2026-06-25T18:00:01.000Z",
  "finishedAt": "2026-06-25T18:00:39.000Z",
  "durationMs": 38120,
  "result": {
    "providers": ["mindbody"],
    "offerings": [
      { "name": "Classic Cut", "price": "$35", "durationMins": 30 },
      { "name": "Hot Towel Shave", "price": "$28", "durationMins": 30 }
    ]
  }
}

Handling errors

Every error follows the same envelope:
{
  "error": {
    "code": "rate_limited",
    "message": "Too many concurrent extractions. Retry shortly."
  }
}
HTTPMeaningRetryable
401Missing, invalid, or revoked keyNo — check your key
409Idempotency conflict — same Idempotency-Key, different payloadNo — use a new key
422Validation failed — fix the request bodyNo
429Rate limited or at capacityYes — back off and retry
404Extraction not found, or not owned by this key (poll)No
When an extraction ends failed, check failure.retryable:
if (job.status === 'failed') {
  if (job.failure?.retryable) {
    // Safe to resubmit (with a fresh Idempotency-Key)
  } else {
    // Permanent error — log and skip
  }
}

Next steps

Detect

Synchronous provider detection — request schema and response fields.

Extract

Async extraction — submit a URL, get a job to poll.

Poll an extraction

Polling semantics and terminal states.

API keys

Create, list, and revoke keys.