Getting started with the API
The TAYO.pro API gives your own software access to your projects, quotes, invoices and reminders. It is meant to be called by a server, never from a browser: an API key in a JavaScript bundle is a published key.
What you need first
Section titled “What you need first”The API is a paid add-on on top of a PLUS subscription. Without it, every
call answers 403 addon_required.
Keys are created from Settings → API, and only an administrator can do it.
Your two keys
Section titled “Your two keys”Every company gets two keys, and the prefix decides everything:
| Key | What it does |
|---|---|
tay_live_… |
Acts on your real data. |
tay_test_… |
Runs a request through the whole chain, then returns a sample response without touching anything. |
The mode therefore appears neither in the URL, nor in the body, nor in a header — only in the key you present.
Authenticating a call
Section titled “Authenticating a call”The key goes in the Authorization header and nowhere else — a key passed as a
query parameter is refused with a 401, even when it is valid.
curl https://staging.tayo.pro/api/v1/ping \ -H "Authorization: Bearer tay_live_your_key"The base URL is https://staging.tayo.pro/api/v1.
Test mode
Section titled “Test mode”A request presented with a tay_test_… key goes through exactly the same chain
as a real one: authentication, quota accounting, and the same validation of
body and parameters. Then it stops before the business logic.
In practice, in test mode:
- nothing is written and nothing is deleted;
- no email, no PDF and no call to Tayo is triggered;
- the response conforms to the production response schema;
- ids are stable between calls —
prj_test_1staysprj_test_1— so your tests can assert against them.
That is what makes going live uneventful: you have already seen the exact shape of every response.
Forcing an error case with Tay-Test-Scenario
Section titled “Forcing an error case with Tay-Test-Scenario”A serious integrator needs to exercise their error branches. The
Tay-Test-Scenario header picks the response test mode should return:
| Scenario | What you get |
|---|---|
success |
The nominal case. This is the default. |
not_found |
The requested resource does not exist. |
validation_error |
The body is refused, with per-field detail. |
send_failed |
Sending to the client failed. |
quota_exceeded |
Your monthly quota is spent. |
Each endpoint accepts a subset of these — send_failed is meaningless on a
read. A value outside that subset answers 400.
Going live
Section titled “Going live”Swap the key. That is all.
URLs, request bodies, response schemas and error codes are identical in both modes — that is the entire point of test mode.
How errors look
Section titled “How errors look”Every failing request returns the same envelope:
{ "error": { "code": "invalid_argument", "message": "The request failed validation.", "details": [ { "field": "amount", "code": "invalid_type", "message": "Expected number" } ] }}details is present only on a validation error.
| Status | code |
When |
|---|---|---|
| 400 | invalid_argument |
The request failed validation. |
| 400 | failed_precondition |
The operation is impossible in the current state. |
| 400 | test_header_in_live_mode |
Tay-Test-Scenario was sent with a live key. |
| 401 | unauthenticated |
Key missing, revoked, or presented another way. |
| 403 | permission_denied |
This key may not perform this action. |
| 403 | addon_required |
The API add-on is not active on the company. |
| 404 | not_found |
The resource does not exist. |
| 409 | already_exists |
The resource already exists. |
| 409 | delivery_in_flight |
The webhook delivery is already queued for another attempt. |
| 409 | endpoint_deleted |
The endpoint this delivery was sent to no longer exists. |
| 409 | endpoint_disabled |
The endpoint this delivery was sent to is disabled. |
| 409 | retry_limit_reached |
The delivery has reached its manual retry limit. |
| 429 | rate_limited |
Too many requests per minute — slow down and retry. See Usage limits. |
| 429 | quota_exceeded |
The monthly quota and its overage allowance are spent. See Usage limits. |
| 500 | internal |
An error on our side. |
| 503 | unavailable |
Temporarily unavailable. |
Messages are English only, and will stay that way: a program reads the
code, and translating the prose would only make what it greps for harder to
find.
If a response departs from what the reference describes, that is a bug and fixing it is included in the add-on: see Support.