Skip to content

Getting started with the API

The TAYO.pro API lets your own software read your projects, on-site jobs, quotes, invoices and payment reminders. In its current version, it only reads: no endpoint creates or sends a document. The exact list is in the reference.

It is meant to be called by a server, never from a browser: an API key in a JavaScript bundle is a published key.

The API is a paid add-on, on top of a PLUS plan subscription. Without it, every authenticated call answers 403 addon_required.

Keys are created from Settings → API, in the web app only, after accepting the API terms of use.

Every company gets two keys, and the prefix decides everything:

Key What it does
tay_live_… The live key: accesses your real data.
tay_test_… The test key: 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.

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.

Fenêtre de terminal
curl https://app.tayo.pro/api/v1/me \
-H "Authorization: Bearer tay_test_your_key"
{ "companyId": "…", "mode": "test" }

GET /me tells you which company and which mode the key belongs to: it is the first call to make to check a key. GET /ping, for its part, needs no key: it only tells you whether the API is answering.

The base URL is https://app.tayo.pro/api/v1.

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 dead 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 from one call to the next — prj_test_1 stays prj_test_1 — so your tests can rely on 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 be able to test 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 values — send_failed is meaningless on a read. Today, a list accepts success and quota_exceeded, and reading a single resource adds not_found. A value outside that subset answers 400.

Swap the key. That is all.

URLs, request bodies, response schemas and error codes are identical in both modes — that is the very point of test mode.

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.
401 unauthenticated Key missing, revoked, or presented the wrong way.
403 permission_denied This key may not do this.
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 delivery is already waiting for another attempt.
409 endpoint_deleted The endpoint of this delivery no longer exists.
409 endpoint_disabled The endpoint of this delivery 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 Service temporarily unavailable.

Messages are in English only, and will stay that way: a program reads the code, and translating the prose would only make what it is really looking 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 API support.