> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bindbee.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Timesheet

> Creates a Time sheet object with the given values.

export const IntegrationSupport = ({category = "HRIS", model, direction = "read"}) => {
  const SHEET_BASE = "https://docs.google.com/spreadsheets/d/e/2PACX-1vTx0G0yItXlZKO4Zep8wstZuvvO7bgOxFXBVK_1vvQnxpG8H2hP9n9M8kmZMfIoo7ZO4e7_utrz3_XB/pub";
  const SHEET_GIDS = {
    HRIS: {
      read: "0",
      write: "1626747715"
    },
    ATS: {
      read: "1962490874"
    },
    LMS: {
      read: "1106223511"
    }
  };
  const LOGO_ROW = "logo link";
  const HEADER_ROW = "model";
  const TYPE_ROW = "connection type";
  const parseCsv = text => {
    const rows = [];
    let row = [];
    let field = "";
    let quoted = false;
    for (let i = 0; i < text.length; i++) {
      const c = text[i];
      if (quoted) {
        if (c === '"') {
          if (text[i + 1] === '"') {
            field += '"';
            i++;
          } else {
            quoted = false;
          }
        } else {
          field += c;
        }
      } else if (c === '"') {
        quoted = true;
      } else if (c === ",") {
        row.push(field);
        field = "";
      } else if (c === "\n" || c === "\r") {
        if (c === "\r" && text[i + 1] === "\n") i++;
        row.push(field);
        rows.push(row);
        row = [];
        field = "";
      } else {
        field += c;
      }
    }
    if (field !== "" || row.length) {
      row.push(field);
      rows.push(row);
    }
    return rows;
  };
  const cell = (row, i) => (row && row[i] || "").trim();
  const parseSheet = (csv, wanted) => {
    const rows = parseCsv(csv);
    let header = null;
    let labelCol = -1;
    rows.slice(0, 12).forEach(r => {
      if (header) return;
      for (let i = 0; i < Math.min(r.length, 6); i++) {
        if (cell(r, i).toLowerCase() === HEADER_ROW) {
          header = r;
          labelCol = i;
          return;
        }
      }
    });
    const find = label => rows.find(r => cell(r, labelCol).toLowerCase() === label);
    const types = header ? find(TYPE_ROW) : null;
    const logos = header ? find(LOGO_ROW) : null;
    if (!header || !types) return null;
    const providers = [];
    for (let i = labelCol + 1; i < header.length; i++) {
      const name = cell(header, i);
      const t = cell(types, i).toUpperCase();
      if (!name || t !== "A" && t !== "S") continue;
      providers.push({
        name,
        type: t === "S" ? "SFTP" : "API",
        col: i,
        uid: name + "#" + i,
        logo: cell(logos, i)
      });
    }
    const target = String(wanted || "").toLowerCase();
    const row = rows.find(r => cell(r, labelCol).toLowerCase() === target);
    if (!providers.length || !row) return null;
    const pool = providers;
    const supported = [];
    pool.forEach(p => {
      const v = cell(row, p.col).toUpperCase();
      if (v === "Y" || v === "B") supported.push({
        ...p
      });
    });
    if (!supported.length) return {
      none: true
    };
    return {
      total: pool.length,
      supported
    };
  };
  const CSS = `
  .bb-is {
    --bb-border: #e5e3df;
    --bb-border-strong: #d4d1cc;
    --bb-bg: #fcfcfb;
    --bb-bg-sub: #f5f4f3;
    --bb-text: #1c1b1a;
    --bb-text-dim: #6e6c68;
    --bb-accent: #f57e21;
    --bb-chip: #eceae7;
    font-size: 14px;
    color: var(--bb-text);
    border: 1px solid var(--bb-border);
    border-radius: 6px;
    background: var(--bb-bg);
    margin: 1.5rem 0;
    overflow: hidden;
  }
  html.dark .bb-is {
    --bb-border: #242424;
    --bb-border-strong: #333333;
    --bb-bg: #090909;
    --bb-bg-sub: #141414;
    --bb-text: #ededed;
    --bb-text-dim: #a1a1a1;
    --bb-chip: #1b1b1b;
  }

  .bb-is-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 11px 14px;
    background: var(--bb-bg-sub);
    border-bottom: 1px solid var(--bb-border);
  }
  .bb-is-title {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-weight: 600;
    font-size: 16px;
  }
  /* Mintlify's <Icon> paints itself via a mask, so this makes it take the
     title's colour instead of staying its own. */
  .bb-is-title .icon { background-color: currentColor !important; }
  .bb-is-count {
    font-size: 12px;
    color: var(--bb-text-dim);
  }

  .bb-is-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 12px 14px;
  }
  /* Collapsed by default: one row of chips, the next row fading out under a
     gradient so it reads as "there is more" rather than as a hard crop. The
     wrapper does the clipping so the chips keep their own padding. */
  .bb-is-chips-wrap { position: relative; }
  .bb-is-chips-wrap[data-open="false"] .bb-is-chips {
    max-height: 47px;
    overflow: hidden;
  }
  .bb-is-fade {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 28px;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(252, 252, 251, 0), var(--bb-bg));
  }
  html.dark .bb-is-fade {
    background: linear-gradient(to bottom, rgba(9, 9, 9, 0), var(--bb-bg));
  }
  .bb-is-toggle {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    border: 1px solid var(--bb-border-strong);
    border-radius: 999px;
    background: var(--bb-bg);
    color: var(--bb-text-dim);
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.5;
    cursor: pointer;
  }
  .bb-is-toggle:hover {
    color: var(--bb-text);
    border-color: var(--bb-text-dim);
  }
  .bb-is-headright {
    display: inline-flex;
    align-items: center;
    gap: 10px;
  }
  .bb-is-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 9px;
    border: 1px solid var(--bb-border);
    border-radius: 999px;
    background: var(--bb-bg-sub);
    font-size: 12.5px;
    line-height: 1.4;
    white-space: nowrap;
  }
  .bb-is-logo {
    width: 15px;
    height: 15px;
    object-fit: contain;
    border-radius: 3px;
    flex: none;
  }
  .bb-is-badge {
    font-size: 9.5px;
    font-weight: 600;
    letter-spacing: 0.03em;
    padding: 1px 5px;
    border-radius: 3px;
    background: var(--bb-chip);
    color: var(--bb-text-dim);
  }
  /* Muted on purpose - the provider name should catch the eye in this list,
     not its connection-type badge. --bb-chip sat too close to the chip's own
     --bb-bg-sub to read as a separate shape, so the fill is a step further
     from it in each theme - darker in light mode, and lighter (not literally
     "darker") in dark mode, since going darker there would fade it into the
     near-black page instead of separating it. */
  .bb-is-badge[data-type="SFTP"] { color: var(--bb-text-dim); background: #ddd9d3; }
  html.dark .bb-is-badge[data-type="SFTP"] { background: #292929; }

  .bb-is-foot {
    padding: 9px 14px;
    border-top: 1px solid var(--bb-border);
    font-size: 14px;
    color: var(--bb-text-dim);
  }
  .bb-is-foot a { color: var(--bb-accent); text-decoration: none; }
  .bb-is-foot a:hover { text-decoration: underline; }

  .bb-is-none {
    padding: 16px 14px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--bb-text-dim);
  }
  .bb-is-none a { color: var(--bb-accent); text-decoration: none; }
  .bb-is-none a:hover { text-decoration: underline; }

  .bb-is-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 28px 14px;
    font-size: 12.5px;
    color: var(--bb-text-dim);
  }
  .bb-is-spinner {
    width: 18px;
    height: 18px;
    border: 2px solid var(--bb-border);
    border-top-color: var(--bb-accent);
    border-radius: 50%;
    animation: bb-is-spin 0.7s linear infinite;
    flex: none;
  }
  @keyframes bb-is-spin {
    to { transform: rotate(360deg); }
  }
  /* Keep a motion cue for anyone who asked for less of it, just a calmer one. */
  @media (prefers-reduced-motion: reduce) {
    .bb-is-spinner { animation-duration: 2.4s; }
  }
  `;
  const [data, setData] = useState(null);
  const [open, setOpen] = useState(false);
  useEffect(() => {
    let live = true;
    const tabs = SHEET_GIDS[category] || ({});
    const gid = tabs[direction];
    if (!gid) return;
    const url = SHEET_BASE + "?gid=" + encodeURIComponent(gid) + "&single=true&output=csv&_=" + Date.now();
    fetch(url, {
      cache: "no-store"
    }).then(res => res.ok ? res.text() : Promise.reject(res.status)).then(text => {
      if (live) setData(parseSheet(text, model) || ({
        hide: true
      }));
    }).catch(() => {
      if (live) setData({
        hide: true
      });
    });
    return () => {
      live = false;
    };
  }, [category, model, direction]);
  if (data && data.hide) return null;
  const none = !!(data && data.none);
  const verb = direction === "write" ? "writing" : "reading";
  const mailto = "mailto:support@bindbee.dev?subject=" + encodeURIComponent("Integration request: " + verb + " " + model + " (" + category + ")");
  const collapsible = !!(data && !none && data.supported.length > 4);
  return <div className="bb-is not-prose">
      <style>{CSS}</style>
      <div className="bb-is-head">
        <span className="bb-is-title">
          <Icon icon="git-fork" size={15} />
          Supported integrations
        </span>
        {data && !none ? <span className="bb-is-headright">
            <span className="bb-is-count">
              {data.supported.length} integration{data.supported.length === 1 ? "" : "s"}
            </span>
            {collapsible ? <button type="button" className="bb-is-toggle" aria-expanded={open} onClick={() => setOpen(!open)}>
                {open ? "Show less" : "Show all"}
              </button> : null}
          </span> : null}
      </div>

      {!data ? <div className="bb-is-loading" role="status">
          <span className="bb-is-spinner" aria-hidden="true" />
          <span>Loading integration support…</span>
        </div> : none ? <div className="bb-is-none">
          No integration supports {verb} {model} yet.{" "}
          <a href={mailto}>Tell us which one you need</a>
        </div> : <div className="bb-is-chips-wrap" data-open={collapsible ? open : true}>
          <div className="bb-is-chips">
            {data.supported.map(p => <span className="bb-is-chip" key={p.uid}>
                {p.logo ? <img className="bb-is-logo" src={p.logo} alt="" loading="lazy" onError={e => {
    e.currentTarget.style.display = "none";
  }} /> : null}
                <span>{p.name}</span>
                {p.type === "SFTP" ? <span className="bb-is-badge" data-type="SFTP">
                    SFTP
                  </span> : null}
              </span>)}
          </div>
          {collapsible && !open ? <span className="bb-is-fade" /> : null}
        </div>}

      <div className="bb-is-foot">
        Coverage varies by integrations {" "}
        <a href="/get-started/model-availability">See the full availability matrix</a>
      </div>
    </div>;
};

<IntegrationSupport category="HRIS" model="Timesheet Entry" direction="write" />

This endpoint creates a Timesheet Entry in the connected HRIS via Bindbee's unified **Time Sheet Entry** model.

## Provider-specific behavior

Different HRIS systems can have slightly different requirements and behaviors when creating timesheet entries. Use the accordions below to see details for each provider.

<AccordionGroup>
  <Accordion title="Bamboo HR">
    <p>
      When the underlying HRIS is <strong>Bamboo HR</strong>, a Timesheet Entry can be created using a payload like:
    </p>

    ```json theme={null}
    {
      "employee": "019ab506-66a2-7f6e-b8da-09d3579a534e",
      "date": "2025-11-24",
      "start_time": "2025-11-24T08:00:00Z",
      "end_time": "2025-11-24T17:00:00Z"
    }
    ```
  </Accordion>

  <Accordion title="Personio">
    <p>
      When the underlying HRIS is <strong>Personio</strong>, a Timesheet Entry can be created using a payload like:
    </p>

    ```json theme={null}
    {
      "employee": "0198e59a-876f-748c-8e38-c56e6246f8aa",
      "break": 8,
      "date": "2025-08-04T08:00:00Z",
      "start_time": "2025-08-04T08:00:00Z",
      "end_time": "2025-08-04T16:00:00Z"
    }
    ```
  </Accordion>

  <Accordion title="Xero">
    <p>
      When the underlying HRIS is <strong>Xero</strong>, a Timesheet Entry can be created using a payload like:
    </p>

    ```json theme={null}
    {
      "employee": "0198e59a-876f-748c-8e38-c56e6246f8aa",
      "start_time": "2025-08-04T08:00:00Z",
      "end_time": "2025-08-04T16:00:00Z"
    }
    ```
  </Accordion>

  <Accordion title="QuickBooks">
    <p>
      When the underlying HRIS is <strong>QuickBooks</strong>, a Timesheet Entry can be created using a payload like:
    </p>

    ```json theme={null}
    {
      "employee": "0198e59a-876f-748c-8e38-c56e6246f8aa",
      "hours_worked": 8,
      "date": "2025-08-04T08:00:00Z",
      "start_time": "2025-08-04T08:00:00Z",
      "end_time": "2025-08-04T16:00:00Z"
    }
    ```
  </Accordion>

  <Accordion title="Workday">
    <p>
      When the underlying HRIS is <strong>Workday</strong>, a Timesheet Entry can be created using a payload like:
    </p>

    ```json theme={null}
    {
      "employee": "019d29f5-07cf-7396-9ae1-34e5b71ad42c",
      "date": "2026-03-26",
      "hours_worked": 7.5,
      "start_time": "2026-03-26T10:00:00Z",
      "end_time": "2026-03-26T17:30:00Z",
      "additional_attributes": {
        "worker_time_block_id": "TEST_BB",
        "time_entry_code_reference_wid": "c20c857a8cf41001aa4db119cb360000",
        "out_reason_reference_id": "Out"
      }
    }
    ```

    <p>
      <strong>Workday-specific requirements:</strong>
    </p>

    <ul>
      <li>
        <code>out\_reason\_reference\_id</code> must be one of: <code>Break</code>, <code>Meal</code>, or <code>Out</code>.
      </li>

      <li>
        For <code>time\_entry\_code\_reference\_wid</code>, search for <strong>All Time Entry Codes</strong> in the Workday portal and use the WID of any suitable code from the displayed list.
      </li>

      <li>
        The selected Time Entry Code must have <strong>Units = Hours</strong>.
      </li>

      <li>
        If the selected Time Entry Code has <strong>Entry Method = In/Out Only</strong>, <code>out\_reason\_reference\_id</code> is required.
      </li>

      <li>
        If the selected Time Entry Code has <strong>Entry Method = Hours Only</strong>, <code>out\_reason\_reference\_id</code> must not be passed.
      </li>
    </ul>
  </Accordion>

  <Accordion title="UKG Ready (Beta)">
    <p>
      Contact <strong><a href="mailto:support@bindbee.dev" target="_blank">Bindbee Support Team</a></strong> for additional details.
    </p>
  </Accordion>

  <Accordion title="ADP (Beta)">
    <p>
      Contact <strong><a href="mailto:support@bindbee.dev" target="_blank">Bindbee Support Team</a></strong> for additional details.
    </p>
  </Accordion>

  <Accordion title="Factorial (Beta)">
    <p>
      Contact <strong><a href="mailto:support@bindbee.dev" target="_blank">Bindbee Support Team</a></strong> for additional details.
    </p>
  </Accordion>
</AccordionGroup>


## OpenAPI

````yaml post /api/hris/v1/timesheet-entry
openapi: 3.1.0
info:
  title: Bindbee APIs
  version: 0.1.0
servers:
  - url: https://api.bindbee.dev
  - url: https://api-eu.bindbee.dev
security: []
paths:
  /api/hris/v1/timesheet-entry:
    post:
      tags:
        - Timesheet Entry
      summary: Create Timesheet
      description: Creates a Time sheet object with the given values.
      operationId: create_timesheet_api_hris_v1_timesheet_entry_post
      parameters:
        - name: x-idempotency-key
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: Key to guarantee idempotent write execution.
            title: X-Idempotency-Key
          description: Key to guarantee idempotent write execution.
      requestBody:
        content:
          application/json:
            schema:
              anyOf:
                - additionalProperties: true
                  type: object
                - type: 'null'
              title: Body
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema: {}
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: >-
                Unix timestamp (seconds since epoch) at which the current
                rate-limit window resets.
              schema:
                type: integer
        '401':
          description: Missing or invalid bearer authentication credentials.
          headers:
            WWW-Authenticate:
              description: Bearer authentication challenge.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: >-
            The credentials are valid but do not permit access to this resource,
            e.g. a connector token used on a different API category or a model
            whose writes are disabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            The X-Idempotency-Key was used with a different body, or its first
            request is still running.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: >-
                Unix timestamp (seconds since epoch) at which the current
                rate-limit window resets.
              schema:
                type: integer
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '501':
          description: The integration does not support this operation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        default:
          description: The vendor's status and body, relayed as the vendor sent them.
      security:
        - HTTPBearer: []
          ConnectorToken: []
components:
  schemas:
    ErrorResponse:
      type: object
      required:
        - detail
      properties:
        detail:
          type: string
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer
      x-default: <BINDBEE_API_KEY>
      description: >-
        Your Bindbee API key, sent as `Authorization: Bearer <BINDBEE_API_KEY>`.
        Required on every request.
    ConnectorToken:
      type: apiKey
      in: header
      name: X-Connector-Token
      x-default: <CONNECTOR_TOKEN>
      description: >-
        The connector token for one customer's connection. This is not your
        Bindbee API key. Required on requests that read or write a single
        customer's data.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.