How the integration works

Everything this demo does is a handful of REST calls and one URL. The code making the calls is js/api.js - about 200 readable lines. The full interactive API reference is at app.vergeag.com/docs.

What this demo does today

sequenceDiagram
    autonumber
    participant YU as Your Ag App (browser)
    participant LA as Launch Pad API
    participant LU as Launch Pad UI

    note over YU,LA: verify the API key
    YU->>LA: GET /api/user/current (X-API-KEY)
    LA-->>YU: user + company access

    note over YU,LA: provision the data hierarchy
    YU->>LA: POST /api/companies/{companyId}/growers
    YU->>LA: POST /api/growers/{growerId}/farms
    YU->>LA: POST /api/fields/save (field + boundary ring)
    LA-->>YU: fieldId + boundaryId

    note over YU,LU: hand over to Launch Pad
    YU->>LU: open /path-planning/boundary/{boundaryId}
(new window, or iframe with ?embedded=true&chrome=false) LU->>LU: user plans the path (existing Launch Pad session)

In a production integration the API calls run from your backend (the API key must never ship to a browser); this demo runs them client-side purely so you can watch the traffic.

Partner mode: provisioning + launch codes (auto sign-in)

With a Partner Admin API key, the demo goes further: your backend creates the Launch Pad user and their org from your own external ids (idempotent - retries never duplicate), then requests a short-lived, single-use launch code. The user's browser exchanges the code for a Launch Pad session on arrival - no sign-up, no sign-in. Try it on the Partner mode page.

sequenceDiagram
    autonumber
    participant YU as YourApp UI
    participant YB as YourApp backend
    participant LA as Launch Pad API
    participant LU as Launch Pad UI

    YU->>YB: user clicks "Open Path Plan"
    note over YB,LA: provision identity from YOUR ids (idempotent)
    YB->>LA: POST /api/partner/users { partnerUserId, email, ... }
    YB->>LA: POST /api/partner/companies { partnerCompanyId, name }
    YB->>LA: POST /api/partner/company-accesses { partnerUserId, partnerCompanyId }
    note over YB,LA: push the data hierarchy (as today)
    YB->>LA: POST growers / farms / fields/save (boundary)
    note over YB,LA: request a launch code
    YB->>LA: POST /api/partner/launch { userId: partnerUserId, returnUrl }
    LA-->>YB: { code, userId, expiresInSec: 600 }
    YB-->>YU: redirect to Launch Pad /launch?code=...&userId=...&returnUrl=...
    YU->>LU: browser opens /launch
    note over LU,LA: exchange the code for a session (code is single-use)
    LU->>LA: POST /api/partner/launch/exchange { code, userId }
    LA-->>LU: JWT session
    LU->>LU: user lands on the boundary, signed in
            

REST call reference

CallPurposeNotes
GET /api/user/current Resolve the user owning the API key Good first call to validate a key. 401 = key invalid/revoked.
GET /api/user/current/companies List companies the key can access All data lives under a company: Company > Grower > Farm > Field > Boundary.
POST /api/companies/{companyId}/growers Create a grower Body {"name", "source": "api", "archived": false}. Keep growerId.
POST /api/growers/{growerId}/farms Create a farm Same body shape. Keep farmId.
POST /api/fields/save Create field + boundary in one call Boundary is coordinate rings of [lon,lat], not GeoJSON. Response returns field.fieldId and vBoundary.boundaryId.
/path-planning/boundary/{boundaryId} UI deep link (not an API call) Open in a new window, or append ?embedded=true&chrome=false for iframes.
POST /api/partner/users Create/find a Launch Pad user from your external user id Partner Admin key only. Idempotent on partnerUserId; email/firstName/lastName required only on first creation.
POST /api/partner/companies Create/find a customer org from your external company id Partner Admin key only. Idempotent on partnerCompanyId; your key's user gets admin access to the org.
POST /api/partner/company-accesses Grant your user access to their org Partner Admin key only. Both referenced by your external ids. Idempotent.
POST /api/partner/launch Issue a single-use launch code (auto sign-in) Partner Admin key only. userId = your external id; response carries the code (10-min TTL) + the Launch Pad user guid. Redirect the browser to /launch?code=…&userId=…&returnUrl=….
POST /api/partner/launch/exchange Exchange the code for a session No API key - the code is the credential. Called by Launch Pad's own /launch page, not by your integration. Single-use: replays fail.

Errors and rate limits your integration should handle

StatusMeaningResponse body
401 API key missing, invalid, expired, or revoked -
402 Account is out of credits for a billable operation {"creditsAvailable", "creditsRequired", "message"}
403 Key is valid but not allowed - e.g. a non-Partner-Admin key calling /api/partner/* {"correlationId", "errorCode": "NotAuthorized", "message"}
429 Rate limit exceeded {"error": {"code": "RATE_LIMIT_EXCEEDED", …}, "limit", "windowSeconds", "retryAfterSeconds"}

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers (visible in the request log on the demo pages) - watch Remaining and back off before you hit the limit; on 429, honor Retry-After.

Embedding contract

Two ways to control the embedded Launch Pad view: