{
  "openapi": "3.1.0",
  "info": {
    "title": "PingPoint Agent API",
    "version": "1.0.0",
    "summary": "Live truck position over an API: create a freight load, the driver joins from an SMS link, then read live position, GPS track and ETA, and confirm delivery.",
    "description": "One key (`sup_agent_…`, issued self-serve in the PingPoint cabinet under Integrations → Agent API) lets your software or AI agent create loads, read live positions and confirm deliveries. Paid operations debit the broker's prepaid balance: $0.65 per load created, $0.02 per position read — everything else is free (see GET /v1/agent/pricing for the live price list; never hardcode prices). Load statuses advance automatically from driver GPS and geofence events, so a status can never be hand-set: external status writes are deliberately closed and answer 410 STATUS_DOOR_CLOSED. Human documentation: https://pingpoint.suverse.io/docs/",
    "contact": {
      "email": "info@suverse.io",
      "url": "https://pingpoint.suverse.io/docs/"
    },
    "termsOfService": "https://pingpoint.suverse.io/legal/terms"
  },
  "servers": [
    {
      "url": "https://api.suverse.io"
    }
  ],
  "security": [
    {
      "agentKey": []
    }
  ],
  "paths": {
    "/v1/agent/loads": {
      "post": {
        "operationId": "createLoad",
        "summary": "Create a freight load ($0.65)",
        "description": "Creates a load under the broker account tied to the key and returns a public tracking link plus a driver link — the driver link is sent to `driverPhone` by SMS automatically. Costs $0.65 from the prepaid balance. `customerRef` doubles as a dedup key: re-sending the same customerRef returns the existing load (HTTP 200, `deduplicated: true`) instead of creating a duplicate. On retries after a network failure pass the same `Idempotency-Key` header so the balance is charged at most once. On 402 nothing is created and nothing is charged.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Pass the same value on retries so the debit and the load are created at most once."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLoadInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Load created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateLoadResult"
                }
              }
            }
          },
          "200": {
            "description": "A load with the same `customerRef` already exists — the existing load is returned, nothing is created or charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DedupCreateLoadResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid fields (`fields` names them), or `driverPhone` does not normalize to E.164 (`code: INVALID_DRIVER_PHONE`).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/MissingFieldsError"
                    },
                    {
                      "$ref": "#/components/schemas/CodedError"
                    }
                  ]
                },
                "examples": {
                  "missingFields": {
                    "value": {
                      "error": "Missing or invalid fields",
                      "fields": [
                        "driverPhone",
                        "pickups.0.zip"
                      ]
                    }
                  },
                  "invalidPhone": {
                    "value": {
                      "error": "driverPhone must be a valid phone number (E.164, e.g. +14155551234).",
                      "code": "INVALID_DRIVER_PHONE"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientFunds"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnknownBroker"
          },
          "503": {
            "$ref": "#/components/responses/BillingUnavailable"
          }
        }
      }
    },
    "/v1/agent/loads/{loadNumber}": {
      "get": {
        "operationId": "getLoadPosition",
        "summary": "Read live position and progress ($0.02)",
        "description": "The load's live state: current status, GPS track (up to 500 most recent points), stops with arrival/departure timestamps, on-time flag, distance covered (haversine over the GPS track, miles) and an ETA block. Costs $0.02 per call from the prepaid balance — every call is billed, do not poll in a tight loop. Statuses are advanced by driver GPS and geofence events, so what you read is backed by recorded position.",
        "parameters": [
          {
            "$ref": "#/components/parameters/loadNumber"
          }
        ],
        "responses": {
          "200": {
            "description": "Live load state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoadPosition"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientFunds"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnknownBroker"
          }
        }
      }
    },
    "/v1/agent/loads/{loadNumber}/status": {
      "patch": {
        "operationId": "updateLoadStatus",
        "summary": "Update load status — deliberately closed (410)",
        "description": "Deliberately closed: every call returns 410 STATUS_DOOR_CLOSED. PingPoint owns the load lifecycle — statuses advance automatically from driver GPS and geofence events (PLANNED → AT_PICKUP → IN_TRANSIT → DELIVERED), so a status can never be hand-set or spoofed. When the BOL is in hand use the delivery-confirm endpoint; anything else is done by the broker in the PingPoint cabinet.",
        "parameters": [
          {
            "$ref": "#/components/parameters/loadNumber"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "PLANNED",
                      "AT_PICKUP",
                      "IN_TRANSIT",
                      "DELIVERED",
                      "CANCELLED"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "410": {
            "description": "Always. External status writes are closed by design.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CodedError"
                },
                "examples": {
                  "doorClosed": {
                    "value": {
                      "error": "This endpoint is closed. PingPoint owns the load lifecycle; AgentOS must not change load status.",
                      "code": "STATUS_DOOR_CLOSED"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/agent/loads/{loadNumber}/delivery-confirm": {
      "post": {
        "operationId": "confirmDelivery",
        "summary": "Confirm delivery — BOL received (free)",
        "description": "For a load waiting at its delivery stop: flips it to DELIVERED and records the BOL timestamp. Free. Idempotent — confirming an already-DELIVERED load just records the timestamp (`idempotent: true`). If the driver has not arrived at the delivery stop yet the call answers 422 (`reason: bol_received_before_geofence_arrive`) — do NOT retry: delivery completes automatically when the driver arrives.",
        "parameters": [
          {
            "$ref": "#/components/parameters/loadNumber"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "bol_received_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the BOL was received, ISO 8601. Defaults to now."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delivery confirmed (or already delivered).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConfirmDeliveryResult"
                },
                "examples": {
                  "confirmed": {
                    "value": {
                      "ok": true,
                      "oldStatus": "AT_DELIVERY",
                      "newStatus": "DELIVERED"
                    }
                  },
                  "idempotent": {
                    "value": {
                      "ok": true,
                      "idempotent": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`bol_received_at` is not a parseable date.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlainError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "The load is not at its delivery stop yet (`reason: bol_received_before_geofence_arrive`) — do not retry — or the key's broker is not registered (`code: UNKNOWN_BROKER`).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/DeliveryNotReadyError"
                    },
                    {
                      "$ref": "#/components/schemas/UnknownBrokerError"
                    }
                  ]
                },
                "examples": {
                  "notAtDelivery": {
                    "value": {
                      "error": "load not at delivery yet",
                      "status": "IN_TRANSIT",
                      "reason": "bol_received_before_geofence_arrive"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/agent/pricing": {
      "get": {
        "operationId": "getPricing",
        "summary": "Current price list (free)",
        "description": "Current USD price per operation. The live price list is the single source of truth — never hardcode prices.",
        "responses": {
          "200": {
            "description": "Price list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pricing"
                },
                "examples": {
                  "current": {
                    "value": {
                      "currency": "USD",
                      "prices": {
                        "load_create": 0.65,
                        "position_read": 0.02,
                        "status_update": 0,
                        "delivery_confirm": 0
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/agent/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Prepaid balance (free)",
        "description": "The broker's prepaid USD balance that pays for load creation and position reads. Top up in the cabinet under Billing. A 402 on a paid call means nothing was charged.",
        "responses": {
          "200": {
            "description": "Balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Balance"
                },
                "examples": {
                  "balance": {
                    "value": {
                      "currency": "USD",
                      "balanceUsd": 12.4
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "agentKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your sup_agent_… key in `Authorization: Bearer sup_agent_…`. Issued self-serve in the PingPoint cabinet (Integrations → Agent API), delivered by e-mail."
      }
    },
    "parameters": {
      "loadNumber": {
        "name": "loadNumber",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "PingPoint load number, e.g. LD-2026-123456.",
        "example": "LD-2026-042317"
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/CodedError"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The load belongs to another broker, or the key's scope forbids the operation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PlainError"
            }
          }
        }
      },
      "NotFound": {
        "description": "No load with this loadNumber.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PlainError"
            }
          }
        }
      },
      "UnknownBroker": {
        "description": "The key's broker is not registered on PingPoint (`code: UNKNOWN_BROKER`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UnknownBrokerError"
            }
          }
        }
      },
      "InsufficientFunds": {
        "description": "The prepaid balance cannot cover this operation. Nothing was created or charged. Top up in the cabinet (Billing) and retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/InsufficientFundsError"
            },
            "examples": {
              "insufficient": {
                "value": {
                  "error": "Insufficient prepaid balance.",
                  "code": "INSUFFICIENT_FUNDS",
                  "balanceUsd": 0.35,
                  "priceUsd": 0.65,
                  "billingUrl": "/app/billing"
                }
              }
            }
          }
        }
      },
      "BillingUnavailable": {
        "description": "Billing backend temporarily unreachable; nothing was charged. Retry later (`code: BILLING_UNAVAILABLE`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/CodedError"
            }
          }
        }
      }
    },
    "schemas": {
      "StopInput": {
        "type": "object",
        "required": [
          "address",
          "city",
          "state",
          "zip"
        ],
        "properties": {
          "address": {
            "type": "string",
            "description": "Street address."
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "Two-letter US state code, e.g. TX."
          },
          "zip": {
            "type": "string"
          },
          "facilityName": {
            "type": "string",
            "description": "Stop name shown to the driver; defaults to the street address."
          },
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "Planned window start, ISO 8601."
          },
          "lat": {
            "type": "number",
            "description": "Pre-geocoded latitude. Only used together with lng."
          },
          "lng": {
            "type": "number",
            "description": "Pre-geocoded longitude. Only used together with lat."
          }
        }
      },
      "CreateLoadInput": {
        "type": "object",
        "required": [
          "driverPhone",
          "pickups",
          "deliveries"
        ],
        "properties": {
          "driverPhone": {
            "type": "string",
            "description": "Driver's phone in E.164, e.g. +14155551234. The driver link is sent to this number by SMS."
          },
          "pickups": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/StopInput"
            },
            "description": "Pickup stops in order. A load may have several."
          },
          "deliveries": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/StopInput"
            },
            "description": "Delivery stops in order."
          },
          "shipperName": {
            "type": "string"
          },
          "carrierName": {
            "type": "string"
          },
          "equipmentType": {
            "type": "string",
            "description": "e.g. VAN, REEFER, FLATBED."
          },
          "customerRef": {
            "type": "string",
            "description": "Your reference (PO number). Doubles as the dedup key: re-sending the same customerRef returns the existing load instead of creating a duplicate."
          },
          "rate": {
            "type": "number",
            "description": "Rate in USD, informational."
          },
          "miles": {
            "type": "number"
          },
          "weight": {
            "type": "number",
            "description": "Cargo weight in pounds."
          },
          "truckNumber": {
            "type": "string",
            "description": "Bind to a known truck as a fallback driver resolution."
          }
        }
      },
      "CreateLoadResult": {
        "type": "object",
        "required": [
          "loadId",
          "loadNumber",
          "trackingLink",
          "driverWebLink",
          "driverAppLink"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "loadId": {
            "type": "string"
          },
          "loadNumber": {
            "type": "string",
            "description": "e.g. LD-2026-042317 — use it for all further calls."
          },
          "trackingLink": {
            "type": "string",
            "format": "uri",
            "description": "Public tracking page for the customer."
          },
          "driverWebLink": {
            "type": "string",
            "format": "uri",
            "description": "Driver onboarding link (web). Sent to driverPhone by SMS automatically."
          },
          "driverAppLink": {
            "type": "string",
            "description": "Driver deep link (pingpoint:// scheme)."
          },
          "driverResolution": {
            "type": "string",
            "enum": [
              "bound",
              "unresolved_truck",
              "none"
            ],
            "description": "bound: attached to a known driver; unresolved_truck: truckNumber matched no driver — send driverWebLink; none: no driver yet."
          },
          "unresolvedTruckNumber": {
            "type": "string"
          }
        }
      },
      "DedupCreateLoadResult": {
        "type": "object",
        "required": [
          "ok",
          "loadId",
          "loadNumber",
          "trackingLink",
          "deduplicated"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "loadId": {
            "type": "string"
          },
          "loadNumber": {
            "type": "string"
          },
          "trackingLink": {
            "type": "string",
            "format": "uri"
          },
          "driverWebLink": {
            "type": "string",
            "format": "uri"
          },
          "driverAppLink": {
            "type": "string",
            "format": "uri"
          },
          "deduplicated": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "PositionStop": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "PICKUP",
              "DELIVERY"
            ]
          },
          "sequence": {
            "type": "integer"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "windowFrom": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "windowTo": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "arrivedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Set by geofence arrival."
          },
          "departedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Set by geofence departure."
          }
        }
      },
      "GpsPoint": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number"
          },
          "lng": {
            "type": "number"
          },
          "speed": {
            "type": [
              "number",
              "null"
            ],
            "description": "Ground speed in mph, rounded to 1 decimal. Null when the fix carries no speed (stored sentinel -1 or missing)."
          },
          "heading": {
            "type": [
              "number",
              "null"
            ],
            "description": "Heading in degrees, 0-359 (0 = north). Null when unknown (stored sentinel -1 or missing)."
          },
          "ts": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LoadPosition": {
        "type": "object",
        "required": [
          "loadNumber",
          "status",
          "createdAt",
          "stops",
          "gpsTrack",
          "pingCount"
        ],
        "properties": {
          "loadNumber": {
            "type": "string"
          },
          "pingpointLoadId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "PLANNED, AT_PICKUP, IN_TRANSIT, AT_DELIVERY, DELIVERED, CANCELLED, … — advanced automatically from driver GPS and geofence events."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "deliveredAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "distanceMiles": {
            "type": [
              "number",
              "null"
            ],
            "description": "Haversine over the FULL GPS track of the load (not just the 500 returned points), miles. Null until there are at least 2 pings."
          },
          "onTime": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Delivered within the delivery window (15 min grace). Null until delivered or when no window is set."
          },
          "delayMinutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "pickupDwellMinutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "deliveryDwellMinutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "stops": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PositionStop"
            }
          },
          "gpsTrack": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GpsPoint"
            },
            "description": "The 500 most recent GPS points of the trip, in chronological order (oldest first). speed is mph, heading is degrees."
          },
          "pingCount": {
            "type": "integer"
          },
          "eta": {
            "type": "object",
            "description": "ETA block computed from the stored route geometry and the latest position; fail-soft — degrades to a reason-only object when there is not enough data.",
            "additionalProperties": true
          }
        }
      },
      "ConfirmDeliveryResult": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "oldStatus": {
            "type": "string"
          },
          "newStatus": {
            "type": "string",
            "const": "DELIVERED"
          },
          "idempotent": {
            "type": "boolean",
            "description": "True when the load was already DELIVERED — the call just recorded the BOL timestamp."
          }
        }
      },
      "Pricing": {
        "type": "object",
        "required": [
          "currency",
          "prices"
        ],
        "properties": {
          "currency": {
            "type": "string",
            "const": "USD"
          },
          "prices": {
            "type": "object",
            "description": "USD price per operation. Keys include load_create, position_read, status_update, delivery_confirm.",
            "additionalProperties": {
              "type": "number"
            }
          }
        }
      },
      "Balance": {
        "type": "object",
        "required": [
          "currency",
          "balanceUsd"
        ],
        "properties": {
          "currency": {
            "type": "string",
            "const": "USD"
          },
          "balanceUsd": {
            "type": "number"
          }
        }
      },
      "PlainError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "CodedError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "description": "Machine-readable code, e.g. STATUS_DOOR_CLOSED, BILLING_UNAVAILABLE, INVALID_DRIVER_PHONE, MISSING_KEY."
          }
        }
      },
      "MissingFieldsError": {
        "type": "object",
        "required": [
          "error",
          "fields"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Dotted paths of missing/invalid fields, e.g. pickups.0.zip."
          }
        }
      },
      "UnknownBrokerError": {
        "type": "object",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "const": "UNKNOWN_BROKER"
          },
          "brokerEmail": {
            "type": "string"
          }
        }
      },
      "DeliveryNotReadyError": {
        "type": "object",
        "required": [
          "error",
          "reason"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Current load status."
          },
          "reason": {
            "type": "string",
            "const": "bol_received_before_geofence_arrive"
          }
        }
      },
      "InsufficientFundsError": {
        "type": "object",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "const": "INSUFFICIENT_FUNDS"
          },
          "balanceUsd": {
            "type": "number",
            "description": "Balance after the check, USD."
          },
          "priceUsd": {
            "type": "number",
            "description": "Price of the rejected operation, USD."
          },
          "billingUrl": {
            "type": "string",
            "description": "Where to top up."
          }
        }
      }
    }
  }
}