API & Webhooks
Programmatic access to your VinSnap Business shop. REST endpoints for customers, jobs, invoices, parts, plus outbound webhooks for every state change. JSON-only, HTTPS-only, predictable.
Overview
The API is REST over HTTPS. All requests and responses are JSON.
Base URL: https://vinsnap.net/.netlify/functions/api.
Endpoints are scoped to the authenticated shop — you'll only ever see your own customers, jobs, etc. There is no concept of cross-shop access. Multi-location organizations on the Pro tier can mint separate API keys per location.
Authentication
Every request must include a bearer token in the Authorization
header. Generate keys at Settings → API Keys.
Authorization: Bearer vsk_live_xxxxxxxxxxxxxxxxxxxxxxxx
Tokens are prefixed: vsk_test_ for sandbox keys (don't
hit production data) and vsk_live_ for production. Keep
live keys server-side — never embed them in browser JavaScript or
mobile bundles.
Rate limits
| Endpoint type | Limit | Window |
|---|---|---|
| Reads (GET) | 600 requests | per minute |
| Writes (POST/PUT/DELETE) | 120 requests | per minute |
| Parts search | 60 requests | per minute |
| VIN decode | 30 requests | per minute |
Responses include rate-limit headers: X-RateLimit-Limit,
X-RateLimit-Remaining, X-RateLimit-Reset
(Unix timestamp). On exceed, you get a 429 with
Retry-After seconds. Burst above the limit and your
key is throttled for 60 seconds.
Errors & status codes
Standard HTTP semantics. Errors return JSON:
{
"success": false,
"error": {
"code": "customer_not_found",
"message": "No customer with id 12345",
"request_id": "req_3KBYZ8"
}
}
| Status | Meaning |
|---|---|
200 OK | Success |
201 Created | Resource created |
400 Bad Request | Invalid input — see error.message |
401 Unauthorized | Missing / invalid bearer token |
403 Forbidden | Token lacks permission for this endpoint |
404 Not Found | Resource doesn't exist (or doesn't belong to your shop) |
429 Too Many Requests | Rate-limited — see Retry-After |
5xx | Server error — safe to retry with backoff |
Customers
Update / delete
Create a customer:
curl -X POST https://vinsnap.net/.netlify/functions/api/customers \
-H "Authorization: Bearer vsk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Sarah Chen",
"phone": "555-0142",
"email": "s.chen@email.com"
}'
Customer vehicles
Vehicle POST with a vin field will auto-decode
the VIN and populate year/make/model/trim. Pass auto_decode: false
to skip that step.
Jobs
GET /jobs accepts query params: ?status=pending|in-progress|completed,
?customer_id=..., ?limit=50&offset=0.
Invoices
POST /invoices/:id/send generates the branded PDF and
emails it to the customer. Returns the PDF URL + the email's
message_id.
Parts
Searches the 1.2M-part TecDoc catalog filtered to the exact vehicle
decoded from the VIN. type is optional (e.g. brake-pads,
oil-filter). Results include OEM cross-references and
stock availability.
Webhooks
Configure outbound webhooks at Settings → Webhooks.
Each event POSTs JSON to your URL with the resource as the payload
and the event type in the X-VinSnap-Event header.
| Event | Fires when |
|---|---|
customer.created | New customer added |
customer.updated | Customer record changed |
job.created | New job opened |
job.status_changed | Kanban move (e.g. pending → in-progress) |
job.completed | Job marked done |
invoice.created | New invoice generated |
invoice.sent | Invoice emailed to customer |
invoice.paid | Invoice marked paid |
Signing
Every payload is signed with HMAC-SHA256. Verify the
X-VinSnap-Signature header against your endpoint secret:
const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
X-VinSnap-Timestamp header).
Retries
We retry failed deliveries with exponential backoff: 1m, 5m, 30m, 2h, 12h, 24h. Total 6 attempts over ~40 hours. Your endpoint should return a 2xx as soon as the event is queued — do the actual work asynchronously.
Webhook delivery logs (last 30 days, with payloads + your response status) are visible at Settings → Webhooks → Activity.
Found a bug or want a new endpoint? Email us.