Overview
Siteline uses a GraphQL API to read and write data between the frontend and backend systems. This API enables third parties to integrate directly with Siteline.
Authentication
All API requests require an API key.
Pass the key as a Bearer token in the
Authorizationheader:
Authorization: Bearer <your token>
Contact your Siteline account partner to receive your company’s API key.
Limitations
Rate Limits: Maximum of 2 requests per second. Exceeding this will return a
429 HTTPresponse.Cold Start: Initial API calls may take up to 20s due to scaling. Subsequent calls should be under 1s.
Query Depth: GraphQL queries are limited to 4 levels of nesting. Going beyond this returns a
400 HTTPresponse.
✅ Example (allowed – 4 levels deep):
query currentCompany {
currentCompany {
# level 1
id
users {
# level 2
company {
# level 3
users {
# level 4
id
}
}
}
}
}
❌ Example (not allowed – 5 levels deep):
query currentCompany {
currentCompany {
# level 1
id
users {
# level 2
company {
# level 3
users {
# level 4
company {
# level 5 -- this query is too deeply nested
id
}
}
}
}
}
}GraphQL API Schema
Schema: View schema in Notion
Postman Collection: Contact [email protected] for access.
Video Walkthrough: Loom demo
Example: Node.js Request
fetch("https://api-external.siteline.com/graphql", {
method: "POST"
headers: {
authorization: "Bearer <your token>",
"content-type": "application/json",
},
body: JSON.stringify({
query: `
query getCurrentCompany {
currentCompany: { id, name }
}
`
})
});Queries
1. currentCompany
Purpose: Verify authentication.
# Query
query currentCompany {
currentCompany {
id
name
}
}
# Response
{
"data": {
"currentCompany": {
"id": "60d45759-f8d4-4106-8858-0f02d2374a4a",
"name": "Manheim Glass"
}
}
}
2. paginatedContracts
Retrieves contracts with optional filters.
Supports pagination (50 per page).
You can provide filters to only get the ones you care about.
# Query
query paginatedContracts($input: GetPaginatedContractsInput!) {
paginatedContracts(input: $input) {
cursor
hasNext
contracts {
id
internalProjectNumber
billingType
percentComplete
project {
projectNumber
}
payApps {
id
billingStart
billingEnd
timeZone
status
}
}
}
}
# Input
{
"input": {
"month": "2023-04",
"payAppStatus": "SUBMITTED_SYNCED_PAID",
"contractStatus": "ACTIVE",
"limit": 50,
"cursor": null // Or the last contract ID was fetched
}
}
# Response
{
"data": {
"paginatedContracts": {
"cursor": "7dcf6d35-935a-43bc-a833-c21c1612f343",
"hasNext": true,
"contracts": [
{
"id": "531dce87-8867-4a59-96e6-313b094a1687",
"internalProjectNumber": "21030161",
"billingType": "LUMP_SUM",
"percentComplete": 1,
"project": {
"projectNumber": "029-393-08505"
},
"payApps": [
{
"id": "b8eb2ebf-14b5-46a3-9bed-9003b14d30d5",
"billingStart": "2022-12-01T06:00:00.000Z",
"billingEnd": "2023-01-01T05:59:59.999Z",
"timeZone": "America/Chicago",
"status": "PAID"
},
...
]
},
...
]
}
}
}
3. contract(id)
Gets details for a single contract.
You probably don’t need this if you already selected the pay app IDs from the previous query.
# Query
query contract($id: ID!) {
contract(id: $id) {
id
payApps {
id
}
}
}
# Input
{
"id": "257ff7ac-dc3e-4a21-b209-6cadfe255a6d"
}
# Response
{
"data": {
"contract": {
"id": "257ff7ac-dc3e-4a21-b209-6cadfe255a6d",
"payApps": [
{
"id": "5b5164bd-16eb-48bd-96a7-45a3929d3e5d"
},
{
"id": "6d88cdce-4c85-4829-abfe-c7809a054d16"
},
{
"id": "1c932f65-d3f3-4884-a5a4-4564975b288b"
}
]
}
}
}
4. payApp(id)
Retrieves details of a single pay app, including billing values and SOV line items.
# Query
query payApp($id: ID!) {
payApp(id: $id) {
id
status
billingStart
billingEnd
timeZone
payAppNumber
currentBilled
currentRetention
totalRetention
previousRetentionBilled
retentionOnly
submittedAt
progress {
id
progressBilled
storedMaterialBilled
totalValue
sovLineItem {
id
code
name
}
}
}
}
# Input
{
"id": "5514674b-a496-4fd8-987a-d5421b639ecc"
}
# Response
{
"data": {
"payApp": {
"id": "5514674b-a496-4fd8-987a-d5421b639ecc",
"status": "PROPOSED",
"billingStart": "2023-03-01T06:00:00.000Z",
"billingEnd": "2023-04-01T04:59:59.999Z",
"timeZone": "America/Chicago",
"payAppNumber": 1,
"currentBilled": 563600,
"currentRetention": 28180,
"totalRetention": 28180,
"previousRetentionBilled": 0,
"retentionOnly": false,
"submittedAt": "2023-03-21T20:39:46.083Z",
"progress": [
{
"id": "fdaa7977-e8ef-40eb-a8c0-ab9070621d76",
"progressBilled": 0,
"storedMaterialBilled": 563600,
"totalValue": 3506800,
"sovLineItem": {
"id": "ff3ffb87-5a7d-4040-b749-f0429999851b",
"code": "1",
"name": "Materials & Labor"
}
}
]
}
}
}
5. paginatedPayApps
Retrieves a paginated list of pay apps with filters.
You can provide filters to only get the ones you care about.
# Query
query paginatedPayApps($input: GetPaginatedPayAppsInput!) {
paginatedPayApps(input: $input) {
cursor
hasNext
payApps {
id
# ...
}
}
}
# Input
{
# Note: all fields in `input` are optional.
# If you don't provide a filter, all pay apps are returned (up to the pagination limit).
# If you just need pay apps submitted in a specific month, only pass `submittedInMonth`, you don't need status/paidInMonth.
# Note that submittedInMonth also includes syncing to a GC portal, which we consider a submission.
"input": {
"status": "PROPOSED", # Or PAID, or SYNCED
"submittedInMonth": "2020-01", # Month in which the pay app was submitted. This also applies to paid pay apps
"paidInMonth": "2020-01", # Month in which the pay app was marked as paid
"limit": 50,
"cursor": null // Or the last pay app ID was fetched
}
}
# Response
{
"data": {
"paginatedPayApps": {
"cursor": "7dcf6d35-935a-43bc-a833-c21c1612f343",
"hasNext": true,
"payApps": [
{
"id": "531dce87-8867-4a59-96e6-313b094a1687",
# ...
}
...
]
}
}
}
FAQ
Q: How do I know when a pay app was submitted?
Use the field
payApp.submittedAt.Returns the most recent time a pay app was proposed or synced to a GC portal.
Returns
nullif currently in draft, even if previously submitted.
Q: Can I use the API to update or push data into Siteline?
No. The Siteline API is read-only for third parties. You can pull and query data, but you cannot create, update, or push data back into Siteline.
