VexSolver

Go Integration

Pure standard library Go integration.

Minimal example (submit + poll)

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "net/url"
    "time"
)

const (
    api    = "https://api.vexsolver.com"
    apiKey = "sk_live_..."
)

func main() {
    target := "https://example.com"

    // 1. Submit
    body, _ := json.Marshal(map[string]string{"url": target})
    req, _ := http.NewRequest("POST", api+"/api/solve", bytes.NewReader(body))
    req.Header.Set("X-API-Key", apiKey)
    req.Header.Set("Content-Type", "application/json")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }

    var sub struct{ TaskID string `json:"taskId"` }
    json.NewDecoder(resp.Body).Decode(&sub)
    resp.Body.Close()

    // 2. Poll
    var result struct {
        Status    string `json:"status"`
        Success   bool   `json:"success"`
        Cookies   string `json:"cookies"`
        UserAgent string `json:"user_agent"`
        ElapsedMs int    `json:"elapsed_ms"`
        Error     string `json:"error"`
    }
    pollURL := api + "/api/getTaskResult?taskId=" + url.QueryEscape(sub.TaskID)
    for i := 0; i < 60; i++ {
        time.Sleep(2 * time.Second)
        req2, _ := http.NewRequest("GET", pollURL, nil)
        req2.Header.Set("X-API-Key", apiKey)
        r2, err := http.DefaultClient.Do(req2)
        if err != nil { continue }
        json.NewDecoder(r2.Body).Decode(&result)
        r2.Body.Close()
        if result.Status != "pending" { break }
    }
    if !result.Success { panic(result.Error) }

    fmt.Println("Cookies:", result.Cookies[:60], "...")
    fmt.Println("UA:    ", result.UserAgent)
    fmt.Println("Elapsed:", result.ElapsedMs, "ms")
}

Reusable client

package vexsolver

import (
    "bytes"
    "context"
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "net/url"
    "time"
)

type Client struct {
    APIKey string
    HTTP   *http.Client
    Base   string
}

type SolveRequest struct {
    URL    string `json:"url"`
    Proxy  string `json:"proxy,omitempty"`
    AppID  string `json:"app_id,omitempty"`
    Fresh  bool   `json:"fresh,omitempty"`
    Vendor string `json:"vendor,omitempty"`
}

type SolveResult struct {
    Status    string            `json:"status"`
    Success   bool              `json:"success"`
    Cookies   string            `json:"cookies"`
    CookieMap map[string]string `json:"cookie_map"`
    UserAgent string            `json:"user_agent"`
    Vendor    string            `json:"vendor"`
    ElapsedMs int               `json:"elapsed_ms"`
    Error     string            `json:"error"`
}

func New(apiKey string) *Client {
    return &Client{
        APIKey: apiKey,
        HTTP:   &http.Client{Timeout: 30 * time.Second},
        Base:   "https://api.vexsolver.com",
    }
}

func (c *Client) Solve(ctx context.Context, req *SolveRequest) (*SolveResult, error) {
    // 1. Submit
    body, _ := json.Marshal(req)
    httpReq, _ := http.NewRequestWithContext(ctx, "POST", c.Base+"/api/solve", bytes.NewReader(body))
    httpReq.Header.Set("X-API-Key", c.APIKey)
    httpReq.Header.Set("Content-Type", "application/json")
    resp, err := c.HTTP.Do(httpReq)
    if err != nil { return nil, err }
    defer resp.Body.Close()
    var sub struct{ TaskID string `json:"taskId"` }
    if err := json.NewDecoder(resp.Body).Decode(&sub); err != nil { return nil, err }
    if sub.TaskID == "" { return nil, errors.New("no taskId returned") }

    // 2. Poll
    pollURL := c.Base + "/api/getTaskResult?taskId=" + url.QueryEscape(sub.TaskID)
    for {
        select {
        case <-ctx.Done():
            return nil, ctx.Err()
        case <-time.After(2 * time.Second):
        }
        r, _ := http.NewRequestWithContext(ctx, "GET", pollURL, nil)
        r.Header.Set("X-API-Key", c.APIKey)
        resp, err := c.HTTP.Do(r)
        if err != nil { return nil, err }
        var out SolveResult
        json.NewDecoder(resp.Body).Decode(&out)
        resp.Body.Close()
        if out.Status == "pending" { continue }
        if !out.Success {
            return &out, fmt.Errorf("solve failed: %s", out.Error)
        }
        return &out, nil
    }
}

Webhook handler

http.HandleFunc("/vexsolver-hook", func(w http.ResponseWriter, r *http.Request) {
    var hook struct {
        TaskID    string `json:"taskId"`
        Success   bool   `json:"success"`
        Cookies   string `json:"cookies"`
        UserAgent string `json:"user_agent"`
        Vendor    string `json:"vendor"`
        Error     string `json:"error"`
    }
    if err := json.NewDecoder(r.Body).Decode(&hook); err != nil {
        http.Error(w, "bad json", http.StatusBadRequest); return
    }
    log.Printf("vexsolver task=%s success=%v vendor=%s", hook.TaskID, hook.Success, hook.Vendor)
    // Store hook.Cookies + hook.UserAgent keyed on hook.TaskID
    w.WriteHeader(http.StatusOK)
})
Context-aware polling
Always pass a context.Context so your service can cancel in-flight solves on shutdown. The example above propagates ctx into the poll loop.