INNOVATECH GROUP
Install this app for quick access.
Highly Technical
Published 17 Apr 2026

Consuming the INNOVATECH Custom API: Authentication, Endpoints, and Rate Limits

14 min Developers
Share

Executive Summary

The INNOVATECH GROUP API provides authenticated, read-only access to billing and profile data for INNOVATECH client accounts. Authentication uses Laravel Sanctum personal access tokens created via POST /api/v1/tokens. Each token can be scoped to one or more of four abilities: invoices:read, invoices:download, quotes:read, and profile:read. All protected endpoints are served under the /api/v1/ base path, require a Bearer token in the Authorization header, and are subject to rate limiting — exceeding the limit returns HTTP 429 with a Retry-After header indicating when requests may resume.

The INNOVATECH GROUP API gives developers programmatic access to billing data (invoices and quotes) and profile information for an authenticated INNOVATECH GROUP client account. It is designed for integrating billing data into internal dashboards, ERP systems, accounting software, or custom reporting tools.

The API is read-only — you can retrieve invoices, download invoice PDFs, list quotes, and read profile data. Token creation is the only write operation.

Prerequisites

Before you begin, make sure you have:

  • An active INNOVATECH GROUP client account with a known email address and password
  • A REST client for testing requests — curl, Postman, Insomnia, or any HTTP library in your preferred programming language
  • Basic familiarity with HTTP methods, headers, and JSON response bodies

Base URL

All API endpoints are served under:

https://{portal-domain}/api/v1/

Replace {portal-domain} with the domain of your INNOVATECH GROUP client portal. All examples in this article use relative paths starting from /api/v1/.

Authentication

The INNOVATECH GROUP API uses Laravel Sanctum personal access tokens for authentication. Tokens are created by exchanging your client account credentials for a bearer token via the token creation endpoint.

Creating a Token

Endpoint: POST /api/v1/tokens

This endpoint is unauthenticated — you do not need an existing token to create one.

Request body:

Field Type Required Description
email string (email) Yes Your INNOVATECH GROUP client account email address
password string Yes Your client account password
device_name string (max 255) Yes A descriptive label for the token (e.g. erp-integration, accounting-sync)
abilities array of strings No The ability scopes to grant. If omitted, the token receives full access (["*"])

Example request:

curl -X POST https://{portal-domain}/api/v1/tokens \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "email": "client@example.com",
    "password": "your-password",
    "device_name": "erp-integration",
    "abilities": ["invoices:read", "invoices:download"]
  }'

Success response — 201 Created:

{
  "token": "1|a1b2c3d4e5f6g7h8i9j0...",
  "abilities": ["invoices:read", "invoices:download"]
}

The token field contains the plain-text token string. This is the only time the full token is returned — store it securely immediately.

The abilities field confirms which abilities were actually granted to the token.

Behaviour when abilities is omitted:

If you do not include the abilities field in your request, the token is granted full access:

{
  "token": "2|k1l2m3n4o5p6q7r8s9t0...",
  "abilities": ["*"]
}

A ["*"] token can access all protected endpoints.

Behaviour when unknown abilities are requested:

If you include ability strings that are not in the allowed set, they are silently removed. Only valid abilities are granted. If the intersection of your requested abilities and the allowed set is empty, the request returns a 422 Unprocessable Entity validation error.

Authentication failure — 422 Unprocessable Entity:

If the email and password combination is invalid, the response contains a validation error on the email field:

{
  "message": "The provided credentials are incorrect.",
  "errors": {
    "email": ["The provided credentials are incorrect."]
  }
}

Ability Scopes

Abilities control which endpoints a token can access. The INNOVATECH GROUP API supports four ability scopes:

Ability Description
invoices:read Intended for invoice retrieval — list and view invoices
invoices:download Download invoice PDF files
quotes:read List and view quotes
profile:read Retrieve the authenticated user's profile information

When creating a token, request only the abilities your integration actually needs. This follows the principle of least privilege — if a token is compromised, the exposure is limited to the abilities it was granted.

Note: The invoice list and detail endpoints (GET /api/v1/invoices and GET /api/v1/invoices/{invoice}) accept any valid authenticated token and do not enforce a specific ability at the route level. Including invoices:read when creating your token is recommended as a scoping convention — it documents the token's intended purpose and future-proofs your integration if ability enforcement is tightened.

Using the Token

Include the token in the Authorization header of every request to a protected endpoint:

Authorization: Bearer 1|a1b2c3d4e5f6g7h8i9j0...

All protected endpoints require this header. Requests without a valid token receive a 401 Unauthenticated response.

Endpoint Reference — Invoices

List Invoices

GET /api/v1/invoices

Returns a paginated list of invoices belonging to the authenticated client account. Results are paginated at 15 items per page.

Example request:

curl -X GET https://{portal-domain}/api/v1/invoices \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Example response — 200 OK:

{
  "data": [
    {
      "id": 1042,
      "invoicenum": "INV-1042",
      "status": "Paid",
      "date": "2026-03-01",
      "duedate": "2026-03-15",
      "datepaid": "2026-03-10",
      "subtotal": "1500.00",
      "tax": "225.00",
      "total": "1725.00",
      "paymentmethod": "payfast",
      "notes": ""
    }
  ],
  "links": {
    "first": "https://{portal-domain}/api/v1/invoices?page=1",
    "last": "https://{portal-domain}/api/v1/invoices?page=3",
    "prev": null,
    "next": "https://{portal-domain}/api/v1/invoices?page=2"
  },
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 15,
    "total": 42
  }
}

To retrieve subsequent pages, append the page query parameter:

GET /api/v1/invoices?page=2

Retrieve a Single Invoice

GET /api/v1/invoices/{invoice}

Returns a single invoice by its ID, scoped to the authenticated client account. Returns 404 Not Found if the invoice does not exist or does not belong to the authenticated user.

Example request:

curl -X GET https://{portal-domain}/api/v1/invoices/1042 \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Example response — 200 OK:

{
  "data": {
    "id": 1042,
    "invoicenum": "INV-1042",
    "status": "Paid",
    "date": "2026-03-01",
    "duedate": "2026-03-15",
    "datepaid": "2026-03-10",
    "subtotal": "1500.00",
    "tax": "225.00",
    "total": "1725.00",
    "paymentmethod": "payfast",
    "notes": ""
  }
}

Download an Invoice PDF

GET /api/v1/invoices/{invoice}/download

Required ability: invoices:download

Returns a JSON response containing the invoice ID and a URL from which the PDF can be downloaded.

Example request:

curl -X GET https://{portal-domain}/api/v1/invoices/1042/download \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Example response — 200 OK:

{
  "data": {
    "invoice_id": 1042,
    "download_url": "https://{portal-domain}/client/invoices/1042/download"
  }
}

Use the download_url to retrieve the actual PDF file. The URL requires the same authenticated session or token depending on your integration approach.

403 Forbidden is returned if the token does not include the invoices:download ability.

Endpoint Reference — Quotes

All quote endpoints require the quotes:read ability on the token.

List Quotes

GET /api/v1/quotes

Returns a paginated list of quotes belonging to the authenticated client account. Results are paginated at 15 items per page.

Example request:

curl -X GET https://{portal-domain}/api/v1/quotes \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Example response — 200 OK:

{
  "data": [
    {
      "id": 87,
      "subject": "Website Redesign Proposal",
      "stage": "Delivered",
      "datecreated": "2026-02-15",
      "validuntil": "2026-03-15",
      "subtotal": "25000.00",
      "tax1": "3750.00",
      "tax2": "0.00",
      "total": "28750.00",
      "customernotes": "Includes responsive design and SEO audit."
    }
  ],
  "links": {
    "first": "https://{portal-domain}/api/v1/quotes?page=1",
    "last": "https://{portal-domain}/api/v1/quotes?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 15,
    "total": 5
  }
}

403 Forbidden is returned if the token does not include the quotes:read ability.

Retrieve a Single Quote

GET /api/v1/quotes/{quote}

Required ability: quotes:read

Returns a single quote by its ID, scoped to the authenticated client account. Returns 404 Not Found if the quote does not exist or does not belong to the authenticated user.

Example request:

curl -X GET https://{portal-domain}/api/v1/quotes/87 \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Example response — 200 OK:

{
  "data": {
    "id": 87,
    "subject": "Website Redesign Proposal",
    "stage": "Delivered",
    "datecreated": "2026-02-15",
    "validuntil": "2026-03-15",
    "subtotal": "25000.00",
    "tax1": "3750.00",
    "tax2": "0.00",
    "total": "28750.00",
    "customernotes": "Includes responsive design and SEO audit."
  }
}

Endpoint Reference — Profile

Retrieve Profile

GET /api/v1/profile

Required ability: profile:read

Returns the profile information of the authenticated client account.

Example request:

curl -X GET https://{portal-domain}/api/v1/profile \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Example response — 200 OK:

{
  "data": {
    "id": 15,
    "firstname": "Jane",
    "lastname": "Mokoena",
    "email": "jane@example.co.za",
    "companyname": "Mokoena Trading (Pty) Ltd",
    "address1": "45 Main Road",
    "city": "Cape Town",
    "state": "Western Cape",
    "postcode": "8001",
    "country": "ZA",
    "phonenumber": "+27211234567"
  }
}

403 Forbidden is returned if the token does not include the profile:read ability.

Rate Limiting

All protected endpoints are subject to rate limiting via the throttle:api middleware. The current limit is 60 requests per minute per authenticated user. Unauthenticated requests (such as token creation) are rate-limited per IP address at the same threshold.

When the limit is exceeded, the API returns:

429 Too Many Requests:

HTTP/1.1 429 Too Many Requests
Retry-After: 30

The Retry-After header indicates the number of seconds to wait before sending another request. This follows the convention defined in RFC 6585.

Best practices for handling rate limits:

  • Implement exponential backoff when you receive a 429 response — wait for at least the duration specified in Retry-After before retrying
  • Avoid polling endpoints at high frequency; cache results locally where possible
  • If your integration processes invoices or quotes in bulk, introduce a short delay between requests to stay within the limit

Error Reference

HTTP Status Meaning Common Cause
401 Unauthenticated Missing or invalid token The Authorization: Bearer {token} header is absent, malformed, or the token has been revoked
403 Forbidden Insufficient ability or resource ownership The token does not have the required ability scope, or the requested resource belongs to a different client account
404 Not Found Resource does not exist The invoice or quote ID does not exist or does not belong to the authenticated user
422 Unprocessable Entity Validation error Invalid credentials on token creation, or no valid abilities in the request
429 Too Many Requests Rate limit exceeded More than 60 requests were sent within the current one-minute window
500 Internal Server Error Server error An unexpected error occurred — contact INNOVATECH GROUP support if the issue persists

Best Practices

Token Management

  • One token per integration: Create a separate token for each system that connects to the API. This makes it easy to revoke access for a specific integration without affecting others.
  • Descriptive device names: Use the device_name field to clearly identify the purpose of each token (e.g. xero-invoice-sync, internal-dashboard, monthly-report-script). This helps you track which tokens are in use and what they are for.
  • Least-privilege abilities: Request only the abilities your integration needs. An accounting sync that only reads invoices should not have profile:read or quotes:read access.

Token Security

  • Treat tokens as secrets: A Sanctum token grants the same access as the client credentials used to create it (within the granted abilities). Store tokens in environment variables or a secrets manager — never in source code, configuration files committed to version control, or client-side code.
  • Do not log tokens: Ensure your application does not write bearer tokens to log files, error reports, or monitoring dashboards.
  • Rotate tokens periodically: Create a new token, update your integration to use the new token, and then revoke the old one. The frequency depends on your security requirements — quarterly rotation is a reasonable starting point for most integrations.

Response Handling

  • Always check HTTP status codes before parsing the response body. A 200 OK confirms the request succeeded; any other status indicates an error condition described in the Error Reference section above.
  • Handle pagination: List endpoints return paginated results. Check the meta.last_page value and iterate through pages as needed to retrieve the full dataset.
  • Cache where appropriate: If your integration reads the same data repeatedly (e.g. an invoice list that updates daily), cache the results locally and refresh on a schedule rather than querying the API on every request.

Getting Help

If you encounter an issue that is not covered by the error reference above, or if you believe the API is not behaving as documented, contact the INNOVATECH GROUP support team by submitting a ticket through the client portal. Include the HTTP method, endpoint path, request headers (with the token redacted), and the full response body in your support request.

Was this helpful?

Let us know if this article answered your question.

We use cookies to keep you signed in and remember your preferences. By continuing, you agree to our Privacy policy.