API Reference

Connect your website or external tools to Check-in ARTISAN

Overview

The Check-in ARTISAN API lets you integrate your field service company with your own website or external applications. Whether you want to display your company profile, synchronize customer and job data, or export invoices to your accounting software, the API gives you full programmatic access to your company data.

Key use cases:

  • Display your company information on your own website.
  • Build a custom customer-facing portal.
  • Export site visit and invoice data to your accounting software.
  • Automate workflows with other business tools.

Base URL

All API requests are made to:

https://checkinartisan.app/api/v1/

All responses are JSON. All dates and timestamps use the ISO 8601 format.


Authentication

Most API endpoints require authentication via a Bearer token. You generate tokens from the admin panel under Check-in ARTISAN Account > API Tokens.

Include the token in the Authorization header of every authenticated request:

Authorization: Bearer your-api-token-here

Each token is scoped to a single company. Multiple tokens can be created for the same company (for example, one per integration).

Security best practices:

  • Treat API tokens like passwords. Never commit them to source code.
  • Use one token per integration so you can revoke individual tokens without affecting others.
  • Revoke tokens immediately when they are no longer needed.

Public Endpoints

These endpoints require no authentication. They are designed for embedding on public-facing websites.

GET /api/v1/companies/{slug}

Returns the public profile of a company.

Parameters: {slug} is the company's unique identifier (visible in your admin URL).

Response:

{
  "data": {
    "slug": "swift-plumbing",
    "name": "Swift Plumbing & Co.",
    "description": "Professional plumbing services for residential and commercial clients.",
    "phone": "+33 1 23 45 67 89",
    "mobile": null,
    "email": "contact@swiftplumbing.fr",
    "website": "https://swiftplumbing.fr",
    "address": "12 Rue des Artisans",
    "address2": null,
    "zip_code": "75001",
    "city": "Paris",
    "country": "FR",
    "opening_hours": { "monday": "8:00-18:00" },
    "social": {
      "facebook": null,
      "instagram": "https://instagram.com/swiftplumbing",
      "twitter": null,
      "youtube": null
    },
    "locale": "fr",
    "currency": "EUR",
    "timezone": "Europe/Paris"
  }
}

Authenticated Endpoints

All endpoints below require a valid Bearer token in the Authorization header.


GET /api/v1/company

Returns the full profile of the company associated with the API token, including the current billing plan.

Response: same as the public company endpoint, plus a "plan" field ("free", "solo", or "pro").


Customers

GET /api/v1/customers

List all customers for your company.

Query parameters:

Parameter Type Description
search string Filter by name, email, or phone.
per_page integer Results per page (default: 25, max: 100).
page integer Page number (default: 1).

Response:

{
  "data": [
    {
      "id": 1,
      "first_name": "Marie",
      "last_name": "Dupont",
      "full_name": "Marie Dupont",
      "email": "marie@example.com",
      "phone": "+33 6 12 34 56 78",
      "mobile": null,
      "address": "12 Rue des Artisans",
      "address2": null,
      "zip_code": "75001",
      "city": "Paris",
      "country": "FR",
      "notes": null,
      "send_sms": true,
      "is_walk_in": false,
      "created_at": "2026-01-15T10:30:00+01:00",
      "updated_at": "2026-01-15T10:30:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 25,
    "total": 72
  }
}

POST /api/v1/customers

Create a new customer.

Request body:

{
  "first_name": "Marie",
  "last_name": "Dupont",
  "email": "marie@example.com",
  "phone": "+33 6 12 34 56 78",
  "mobile": "+33 7 98 76 54 32",
  "address": "12 Rue des Artisans",
  "address2": "Apt 3B",
  "zip_code": "75001",
  "city": "Paris",
  "country": "FR",
  "notes": "Prefers morning appointments.",
  "send_sms": true
}
Field Type Required Description
first_name string Yes First name (max 255).
last_name string Yes Last name (max 255).
email string No Email address.
phone string No Phone number (max 50).
mobile string No Mobile number (max 50).
address string No Street address line 1 (max 255).
address2 string No Street address line 2 (max 255).
zip_code string No Postal code (max 20).
city string No City (max 255).
country string No ISO 3166-1 alpha-2 country code (e.g. "FR").
notes string No Internal notes (max 5000 characters).
send_sms boolean No Whether to include this customer in SMS reminders.

Response (201): the created customer object (same fields as the list response).

GET /api/v1/customers/{id}

Retrieve a single customer, including their jobs.

Response: same fields as the list response, plus a jobs array:

{
  "data": {
    "id": 1,
    "first_name": "Marie",
    "last_name": "Dupont",
    "full_name": "Marie Dupont",
    "email": "marie@example.com",
    "phone": "+33 6 12 34 56 78",
    "mobile": null,
    "address": "12 Rue des Artisans",
    "address2": null,
    "zip_code": "75001",
    "city": "Paris",
    "country": "FR",
    "notes": null,
    "send_sms": true,
    "is_walk_in": false,
    "created_at": "2026-01-15T10:30:00+01:00",
    "updated_at": "2026-01-15T10:30:00+01:00",
    "jobs": [
      { "id": 12, "title": "Bathroom plumbing repair" }
    ]
  }
}

PUT /api/v1/customers/{id}

Update a customer. Send only the fields you want to change. Accepts the same fields as POST /api/v1/customers, all optional.

DELETE /api/v1/customers/{id}

Delete a customer. Returns 204 No Content.


Jobs

GET /api/v1/jobs

List all jobs for your company.

Query parameters:

Parameter Type Description
customer_id integer Filter by customer ID.
status string Filter by status (draft, open, in_progress, completed, cancelled).
per_page integer Results per page (default: 25, max: 100).
page integer Page number (default: 1).

Response:

{
  "data": [
    {
      "id": 12,
      "customer_id": 1,
      "job_type_id": 3,
      "title": "Bathroom plumbing repair",
      "description": "Replace mixer tap and re-seal bath.",
      "address": "12 Rue des Artisans, Paris",
      "status": "in_progress",
      "created_at": "2026-02-01T09:00:00+01:00",
      "updated_at": "2026-02-10T14:30:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 2,
    "per_page": 25,
    "total": 47
  }
}

POST /api/v1/jobs

Create a new job record.

Field Type Required Description
customer_id integer Yes ID of the customer this job belongs to.
title string Yes Job title (max 255).
job_type_id integer No ID of the job type.
description string No Job description (max 5000).
address string No Site address (max 255).
status string No Initial status: draft, open, in_progress, completed, or cancelled.

Response (201): the created job object.

GET /api/v1/jobs/{id}

Retrieve a single job, including customer details, job type, and site visit count.

Response:

{
  "data": {
    "id": 12,
    "customer_id": 1,
    "job_type_id": 3,
    "title": "Bathroom plumbing repair",
    "description": "Replace mixer tap and re-seal bath.",
    "address": "12 Rue des Artisans, Paris",
    "status": "in_progress",
    "created_at": "2026-02-01T09:00:00+01:00",
    "updated_at": "2026-02-10T14:30:00+01:00",
    "customer": {
      "id": 1,
      "full_name": "Marie Dupont"
    },
    "job_type": {
      "id": 3,
      "name": "Plumbing"
    },
    "site_visits_count": 2
  }
}

The job_type.name field is returned in the locale of the company (en or fr).

PUT /api/v1/jobs/{id}

Update a job. Send only the fields you want to change. Accepts job_type_id, title, description, address, and status.

DELETE /api/v1/jobs/{id}

Delete a job record. Returns 204 No Content.


Site Visits

GET /api/v1/site-visits

List site visits for your company.

Query parameters:

Parameter Type Description
from string Start date filter (YYYY-MM-DD).
to string End date filter (YYYY-MM-DD).
customer_id integer Filter by customer ID.
job_id integer Filter by job ID.
status string Filter by status (scheduled, completed, cancelled).
per_page integer Results per page (default: 25, max: 100).
page integer Page number.

Response:

{
  "data": [
    {
      "id": 7,
      "job_id": 12,
      "customer_id": 1,
      "team_member_id": 2,
      "scheduled_at": "2026-03-20T09:00:00+01:00",
      "duration_minutes": 120,
      "status": "scheduled",
      "notes": "Customer will be home from 9am.",
      "created_at": "2026-03-01T11:00:00+01:00",
      "updated_at": "2026-03-01T11:00:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 25,
    "total": 5
  }
}

POST /api/v1/site-visits

Create a new site visit.

Field Type Required Description
job_id integer Yes ID of the job this visit is associated with.
scheduled_at string Yes Scheduled date and time (ISO 8601, e.g. "2026-03-20T09:00:00").
customer_id integer No Customer ID (defaults to the job's customer).
duration_minutes integer No Estimated duration in minutes (min: 1).
notes string No Internal notes for the visit (max 2000).
status string No Initial status: scheduled, completed, or cancelled.
team_member_id integer No ID of the team member assigned to this visit.

Response (201): the created site visit object.

GET /api/v1/site-visits/{id}

Retrieve a single site visit with job, customer, and team member details.

Response:

{
  "data": {
    "id": 7,
    "job_id": 12,
    "customer_id": 1,
    "team_member_id": 2,
    "scheduled_at": "2026-03-20T09:00:00+01:00",
    "duration_minutes": 120,
    "status": "scheduled",
    "notes": "Customer will be home from 9am.",
    "created_at": "2026-03-01T11:00:00+01:00",
    "updated_at": "2026-03-01T11:00:00+01:00",
    "job": {
      "id": 12,
      "title": "Bathroom plumbing repair"
    },
    "customer": {
      "id": 1,
      "full_name": "Marie Dupont"
    },
    "team_member": {
      "id": 2,
      "name": "Jean Martin"
    }
  }
}

PUT /api/v1/site-visits/{id}

Update a site visit. Send only the fields you want to change. Accepts scheduled_at, duration_minutes, notes, status, and team_member_id.

DELETE /api/v1/site-visits/{id}

Delete a site visit. Returns 204 No Content.


Invoices

Invoices use an immutable sequential numbering system. For audit integrity, invoices cannot be updated or deleted via the API.

GET /api/v1/invoices

List invoices for your company.

Query parameters:

Parameter Type Description
from string Invoice creation date start (YYYY-MM-DD).
to string Invoice creation date end (YYYY-MM-DD).
customer_id integer Filter by customer ID.
paid boolean Filter by paid status.
per_page integer Results per page (default: 25, max: 100).
page integer Page number.

Response:

{
  "data": [
    {
      "id": 42,
      "invoice_number": "FA260200042",
      "customer_id": 1,
      "paid": true,
      "total_with_tax": 180.00,
      "notes": "Thank you for choosing us!",
      "created_at": "2026-02-15T10:00:00+01:00",
      "updated_at": "2026-02-15T10:00:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 2,
    "per_page": 25,
    "total": 38
  }
}

GET /api/v1/invoices/{id}

Retrieve a single invoice with its line items and customer details.

Response:

{
  "data": {
    "id": 42,
    "invoice_number": "FA260200042",
    "customer_id": 1,
    "paid": true,
    "total_with_tax": 180.00,
    "notes": "Thank you for choosing us!",
    "created_at": "2026-02-15T10:00:00+01:00",
    "updated_at": "2026-02-15T10:00:00+01:00",
    "customer": {
      "id": 1,
      "full_name": "Marie Dupont",
      "email": "marie@example.com"
    },
    "lines": [
      {
        "id": 101,
        "item_id": 5,
        "description": "Plumbing repair - bathroom",
        "quantity": 1,
        "unit_price_with_tax": 180.00,
        "discount_percent": 0,
        "line_total_with_tax": 180.00
      }
    ]
  }
}

POST /api/v1/invoices

Create a new invoice. The invoice number is assigned automatically.

Request body:

{
  "customer_id": 1,
  "paid": false,
  "notes": "Thank you for choosing us!",
  "lines": [
    {
      "item_id": 5,
      "description": "Plumbing repair - bathroom",
      "quantity": 1,
      "price_with_tax": 180.00,
      "discount": 0
    }
  ]
}
Field Type Required Description
customer_id integer Yes ID of the customer.
paid boolean No Whether the invoice is already paid (default: false).
notes string No Notes printed on the invoice (max 5000).
lines array No Array of line items.
lines[].item_id integer No ID of the catalog item.
lines[].description string No Line item description (max 1000).
lines[].quantity number Yes* Quantity (required when lines are provided, min: 0.01).
lines[].price_with_tax number Yes* Unit price including tax (required when lines are provided, min: 0).
lines[].discount number No Discount percentage applied to this line (0-50).

*Required only when the lines array is present.

Response (201): the created invoice object in the same format as GET /api/v1/invoices/{id}.


Error Responses

The API returns standard HTTP status codes. Error responses include a JSON body with an error field and an optional messages field for validation errors.

Code Meaning
401 Unauthenticated. Token is missing or invalid.
403 Forbidden. You do not have access to the requested resource.
404 Resource not found.
422 Validation error. Check the messages field.
429 Too many requests. Limit: 60 per minute per token.
500 Internal server error.

Example validation error:

{
  "error": "Validation failed.",
  "messages": {
    "first_name": ["The first name field is required."],
    "email": ["The email must be a valid email address."]
  }
}

Rate Limiting

The API enforces rate limiting to ensure fair use and system stability. Requests are limited to 60 per minute per API token. If you exceed this limit, you will receive a 429 Too Many Requests response.


Pagination

All list endpoints return paginated results. The response includes a meta object:

{
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 25,
    "total": 118
  }
}

Use the page and per_page query parameters to navigate through results.


Getting Started

  1. Log in to your Check-in ARTISAN admin panel.
  2. Go to Check-in ARTISAN Account > API Tokens.
  3. Click Generate token, give it a name, and copy the token displayed.
  4. Use the token in the Authorization: Bearer header for all authenticated requests.
  5. Test with a simple request to /api/v1/company to verify your token works.

Support

If you need help integrating the API, contact us through the Contact page or consult the full documentation.