For companiesFor contractors
Developers

PeerToSite Employer API

A real, working JSON API over the same data your PeerToSite dashboard uses — postings, assignments, and invoices. Every example on this page is live; there's nothing here that isn't actually implemented.

Getting Started

Welcome to the PeerToSite Employer API v1. It's a plain JSON REST API over HTTPS — the same data model your PeerToSite dashboard reads and writes to, exposed for your own scripts and integrations.

Version 1 covers dispatch requests end to end — so a ticket in your service desk can become a PeerToSite dispatch, stay in step with it, and close itself — plus reading postings, assignments and invoices. Bidding, check-ins and payment are dashboard-only.

Authentication

Every request is authenticated with an API key, scoped to a single company. A Company Manager generates one under Settings → Integrations → API Keys — it's shown once, so save it somewhere safe. A key is read only or read and write; a read-only key gets 403 on anything that changes data. Each key is limited to 120 requests a minute (429 with Retry-After beyond that).

Note for anyone comparing this to other platforms: this is a single long-lived bearer key, not an OAuth2 client-credentials exchange. Simpler, at the cost of not supporting token expiry or scoped grants yet.

Example

curl https://YOUR-PeerToSite-HOST/api/v1/postings \
  -H "Authorization: Bearer peertosite_live_xxxxxxxxxxxxxxxxxxxxxxxx"

A missing or invalid key returns 401 Unauthorized.

Response Format

Every response — success or error — is wrapped in the same envelope:

{
  "meta": {
    "status_code": 200,
    "version": 1,
    "timestamp": 1755781200
  },
  "response": { ... }
}

JSON only, no XML output option — one less format to keep in sync while the API is this new.

Errors

Errors use standard HTTP status codes. The error message is in response.error:

{
  "meta": { "status_code": 404, "version": 1, "timestamp": 1755781200 },
  "response": { "error": "No such posting" }
}
CodeMeaning
401Missing, malformed, or revoked API key
404The resource doesn't exist, or doesn't belong to your company
422The request body is missing a required field or has the wrong type
GET/api/v1/dispatch-items

The service items you can request (each has a service_item_id) and the urgency levels (critical, high, medium, low). Map your ticket categories and priorities to these once. Urgency sets the price level — and a Critical or High request sent while its location is closed (outside the working hours set in Sites) is billed at the Critical level; the request's after_hours says so — so make that mapping deliberately.

POST/api/v1/dispatch-requests

Creates a dispatch request, exactly as the form does (your company needs the Dispatch service and a plan). The location is one of your sites, by your own store number.

curl -X POST https://YOUR-PeerToSite-HOST/api/v1/dispatch-requests \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: INC0012345" \
  -d '{"site_code": "104", "service_item_id": "…", "urgency": "medium",
       "title": "PIN pad offline at lane 3", "description": "No power since 9am.",
       "reference": "INC0012345", "asset_tag": "PP-104-1"}'

Send an Idempotency-Key — the ticket's own id is ideal. If the same key arrives again, PeerToSite returns the first request (200) instead of creating a second, so a retry never books two visits. asset_tag is optional. A problem with the request is a 422 saying what's wrong.

GET/api/v1/dispatch-requests/{id}

One request: status (matching, offered, accepted, escalated, unfilled, canceled), job_status (open, assigned, in_progress, pending_approval, disputed, completed, canceled), your reference, and the times — requested_at, accepted_at, expected_arrival, arrive_by, checked_in_at, signed_off_at. GET /api/v1/dispatch-requests?reference=INC0012345 finds requests by your ticket number; without it, the newest 100.

Responses never include a technician's name or contact details — you reach them through the job chat (below).

PATCH/api/v1/dispatch-requests/{id}

The ticket was edited: send any of title, description, reference. The title and description can change until the technician checks in (409 after); the reference at any time. The technician is told when the details change.

POST/api/v1/dispatch-requests/{id}/messages

A ticket comment: {"body": "The back door code is 4471"}. It appears in the job chat, where the technician sees it. The technician's replies come to you as dispatch.message webhooks. Like any chat message, one containing a phone number or email address is flagged to PeerToSite.

POST/api/v1/dispatch-requests/{id}/cancel

The ticket was canceled: the visit is canceled and the firm is told. This follows the same rule as the Cancel button — only until the technician checks in. After that PeerToSite answers 409 and nothing changes, so a ticket closed by mistake can't erase a visit in progress. Once the technician has told PeerToSite they're on the way, cancelling is charged the request's travel fee plus tax — the same as the Cancel button — and the invoice appears under Payments. An optional {"reason": "…"} is kept in your audit log.

Webhooks

Instead of asking PeerToSite over and over, give PeerToSite an address and it calls you when a dispatch job changes. A Company Manager adds one under Settings → Integrations → Webhooks and picks the events:

dispatch.requested, dispatch.accepted, dispatch.arrival_confirmed, dispatch.checked_in, dispatch.signed_off, dispatch.completed, dispatch.canceled, dispatch.unfilled, dispatch.late, dispatch.message, dispatch.updated.

POST https://yourcompany.example/peertosite-webhook
X-PeerToSite-Event: dispatch.checked_in
X-PeerToSite-Delivery: 5f0c…          (unique per message — use it to ignore a repeat)
X-PeerToSite-Timestamp: 1791230000
X-PeerToSite-Signature: sha256=3b1f…

{"event": "dispatch.checked_in", "sent_at": "2026-10-06T14:02:11+00:00",
 "dispatch_request": {"id": "…", "reference": "INC0012345", "status": "accepted",
   "job_status": "in_progress", "checked_in_at": "2026-10-06T14:02:09+00:00", …}}

Check the signature before trusting a message: compute HMAC-SHA256 of <X-PeerToSite-Timestamp>.<the raw body> with your webhook's signing secret, and compare it with the value after sha256=. Reject a timestamp more than a few minutes old.

Answer with any 2xx within 5 seconds. Anything else is tried again — six times over about fifteen hours — and every attempt is in your Delivery Log. Your address must be https on the public internet; PeerToSite doesn't follow redirects. Twenty failures in a row switch the webhook off until you turn it back on.

A message carries the request's id, your reference, its stage and times — and, for dispatch.message, the message text. Never a technician's name or contact details. It is sent to the address you give, wherever that system is hosted.

GET/api/v1/postings

Lists your company's postings, most recent first (up to 100).

Request

curl https://YOUR-PeerToSite-HOST/api/v1/postings \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY"

Response

{
  "meta": { "status_code": 200, "version": 1, "timestamp": 1755781200 },
  "response": [
    {
      "id": "b6e1...c02f",
      "title": "Loading dock cleanup",
      "status": "open",
      "visibility": "open",
      "currency_code": "USD",
      "budget_min": 400.00,
      "budget_max": 500.00,
      "work_category_id": "8a21...9d40",
      "created_at": "2026-08-19T14:02:11+00:00"
    }
  ]
}
POST/api/v1/postings

Creates a new posting in draft status — the same state a posting starts in when created from the dashboard.

Request

curl -X POST https://YOUR-PeerToSite-HOST/api/v1/postings \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Loading dock cleanup",
    "scope_of_work": "Sweep and pressure-wash the rear loading dock.",
    "work_category_id": "8a21...9d40",
    "currency_code": "USD",
    "budget_min": 400,
    "budget_max": 500
  }'

Body parameters

FieldTypeRequired
titlestringYes
scope_of_workstringYes
work_category_iduuidYes
currency_codestringYes
budget_min / budget_maxnumberNo
location_addressstringNo
required_skillsarray of stringsNo

Response — 201 Created

{
  "meta": { "status_code": 201, "version": 1, "timestamp": 1755781200 },
  "response": {
    "id": "b6e1...c02f",
    "title": "Loading dock cleanup",
    "status": "draft",
    "currency_code": "USD",
    "budget_min": 400.00,
    "budget_max": 500.00,
    "created_at": "2026-08-19T14:02:11+00:00"
  }
}
GET/api/v1/postings/{id}

Returns a single posting. 404s if it doesn't exist or belongs to a different company.

curl https://YOUR-PeerToSite-HOST/api/v1/postings/b6e1...c02f \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY"
GET/api/v1/assignments

Lists your company's assignments — postings that have been awarded and are underway or complete.

curl https://YOUR-PeerToSite-HOST/api/v1/assignments \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY"

Response

{
  "meta": { "status_code": 200, "version": 1, "timestamp": 1755781200 },
  "response": [
    {
      "id": "4f2a...7e11",
      "title": "Loading dock cleanup",
      "status": "in_progress",
      "worker_id": "9c31...aa02",
      "bid_request_id": "b6e1...c02f",
      "scheduled_start": "2026-08-24T13:00:00+00:00",
      "created_at": "2026-08-20T09:15:00+00:00"
    }
  ]
}
GET/api/v1/assignments/{id}

Returns a single assignment, including its schedule and SLA due date if one is set.

curl https://YOUR-PeerToSite-HOST/api/v1/assignments/4f2a...7e11 \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY"
GET/api/v1/invoices

Lists invoices submitted to your company, most recently submitted first.

curl https://YOUR-PeerToSite-HOST/api/v1/invoices \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY"

Response

{
  "meta": { "status_code": 200, "version": 1, "timestamp": 1755781200 },
  "response": [
    {
      "id": "1a9e...5b30",
      "invoice_number": "INV-1042",
      "status": "paid",
      "worker_id": "9c31...aa02",
      "subtotal_amount": 450.00,
      "currency_code": "USD",
      "submitted_at": "2026-08-24T16:20:00+00:00",
      "approved_at": "2026-08-24T16:40:00+00:00"
    }
  ]
}
GET/api/v1/invoices/{id}

Returns a single invoice.

curl https://YOUR-PeerToSite-HOST/api/v1/invoices/1a9e...5b30 \
  -H "Authorization: Bearer $PEERTOSITE_API_KEY"