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.