Read and write your shop's jobs, customers, quotes, and invoices.
A REST API for building integrations โ Zapier workflows, custom automations, or anything else your shop needs to connect to PrintSked.
Authentication
Every request needs an API key, sent as a bearer token.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Create a key from inside PrintSked under Settings โ Integrations โ API Keys. Each key can be scoped to specific resources and set to read-only or read + write โ write access (creating or updating records) requires a key with write permission.
Base URL
https://hfypdyhmafppzjktlvoz.supabase.co/functions/v1/api-v1
This URL is the same for every shop โ your API key is what identifies your account, not the URL.
Resources
Every record is otherwise a free-form set of fields โ send any additional fields your workflow needs (notes, custom identifiers, etc.) and they'll be stored on the record.
jobs
Print jobs in production. Required on create: customer, product
customers
Customer records. Required on create: name
quotes
Quotes sent to customers. No fields are required on create.
invoices
Invoices billed to customers. Required on create: customer
Reading records
Lists records for a resource, newest first by default, or fetch a single record by id.
/{resource}| Param | Description |
|---|---|
limit | Max results per page. Default 25, max 100. |
offset | Pagination offset. Default 0. |
since / until | ISO date range filter on createdAt. |
sort | created_at (default) or updated_at. |
order | asc or desc (default). |
| Resource-specific filters | e.g. ?status=unpaid on invoices, ?customer=Acme on jobs โ see the field reference for which fields are filterable per resource. |
curl "https://hfypdyhmafppzjktlvoz.supabase.co/functions/v1/api-v1/customers?limit=5" \ -H "Authorization: Bearer sk_live_..."
{
"data": [
{
"id": "a4068ff5-32f4-4819-a22e-a5f8557ac822",
"name": "Sameer",
"email": "sameer@example.com",
"phone": "5544554455",
"company": "SC",
"tier": "wholesale",
"createdAt": "2026-08-01T17:40:42.876043+00:00",
"updatedAt": "2026-08-01T17:44:17.481665+00:00"
}
],
"pagination": { "limit": 5, "offset": 0, "total": 42 }
}
/{resource}/{id}Fetches a single record by id.
curl "https://hfypdyhmafppzjktlvoz.supabase.co/functions/v1/api-v1/customers/a4068ff5-32f4-4819-a22e-a5f8557ac822" \ -H "Authorization: Bearer sk_live_..."
Creating records
/{resource}Creates a new record. Requires a key with write permission. Send the required fields for that resource plus any extra fields you want stored.
curl -X POST "https://hfypdyhmafppzjktlvoz.supabase.co/functions/v1/api-v1/jobs" \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{"customer":"Acme Co","product":"Vinyl Banner"}'
{
"id": "c2d337ef-720a-4723-9c4f-75549ae2a3f6",
"customer": "Acme Co",
"product": "Vinyl Banner",
"createdAt": "2026-09-03T18:57:36.318214+00:00",
"updatedAt": "2026-09-03T18:57:36.318214+00:00"
}
Responses are 201 Created on success. A 413 is returned if the request body exceeds 256KB.
Updating records
/{resource}/{id}Updates an existing record. Requires a key with write permission. Send only the fields you want to change.
curl -X PATCH "https://hfypdyhmafppzjktlvoz.supabase.co/functions/v1/api-v1/jobs/c2d337ef-720a-4723-9c4f-75549ae2a3f6" \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{"product":"18oz Vinyl Banner"}'
Field reference
A few fields on each resource are protected: some never leave the API in either direction, and some are visible on GET but can't be set via POST/PATCH because PrintSked only ever changes them through its own guarded logic (payment recording, margin calculations, etc.).
| Resource | Never exposed | Read-only (visible, not settable) |
|---|---|---|
jobs | internalNotes | laborCost, materialCost, customerId |
customers | internalNotes | tier, creditLimit, currentBalance, depositRequired, paymentTerms, totalLifetimeValue, totalJobs |
quotes | internalNotes | total |
invoices | โ | amount, balance, status, paymentHistory |
Rate limits
Requests are limited to 120 per minute per API key, and 300 per minute in total across every key your shop has issued. Every response includes headers showing where you stand:
X-RateLimit-Limit: 120 X-RateLimit-Remaining: 117 X-RateLimit-Shop-Limit: 300 X-RateLimit-Shop-Remaining: 284
Exceeding a limit returns 429 Too Many Requests with a Retry-After header.
Idempotency
To safely retry a POST without risking a duplicate record, send an Idempotency-Key header with a unique value. Retrying with the same key returns the original response instead of creating a second record.
curl -X POST ".../api-v1/customers" \ -H "Authorization: Bearer sk_live_..." \ -H "Idempotency-Key: my-unique-request-id-123" \ -H "Content-Type: application/json" \ -d '{"name":"Acme Co"}'
Errors
| Status | Meaning |
|---|---|
400 | Invalid request โ missing a required field, bad query parameter, etc. |
401 | Missing, invalid, revoked, or expired API key. |
403 | The key doesn't have access to this resource, or is read-only and you attempted a write. |
404 | Unknown resource or record id. |
413 | Request body larger than 256KB. |
429 | Rate limit exceeded โ see Rate limits. |
Error responses are JSON with a human-readable message:
{ "error": "This API key does not have access to \"invoices\"" }