Skip to main content
All GraphQL requests to the Pylon API require authentication using OAuth Bearer tokens.

Authentication header

Include your access token in the Authorization header:
Authorization: Bearer YOUR_ACCESS_TOKEN

Making authenticated requests

Using fetch

const response = await fetch("https://pylon.mortgage/graphql", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    query: `
      query GetDeals {
        deals(first: 10) {
          edges {
            node {
              id
              friendlyId
            }
          }
        }
      }
    `,
  }),
});

Using GraphQL client

Most GraphQL clients support setting default headers:
import { GraphQLClient } from "graphql-request";

const client = new GraphQLClient("https://pylon.mortgage/graphql", {
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

const data = await client.request(`
  query GetDeals {
    deals(first: 10) {
      edges {
        node {
          id
          friendlyId
        }
      }
    }
  }
`);

Getting access tokens

Access tokens are obtained through the OAuth 2.0 client credentials grant. See the Authentication guide for details on:
  • Obtaining client credentials
  • Exchanging credentials for tokens
  • Requesting a new token when the cached one expires

Token expiration

Access tokens are issued with a fixed lifetime (roughly 24 hours). There is no refresh-token grant — when a token expires you simply request a brand-new one from the token endpoint using the same client credentials. Cache the token along with its expiry and re-request when it’s expired:
const TOKEN_ENDPOINT = "https://auth.pylon.mortgage/oauth/token";

let cachedToken = null;
let tokenExpiresAt = 0;

async function getAccessToken() {
  // Reuse the cached token while it's still valid.
  if (cachedToken && Date.now() < tokenExpiresAt) {
    return cachedToken;
  }

  // Expired (or never fetched): request a brand-new token.
  const response = await fetch(TOKEN_ENDPOINT, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "client_credentials",
      client_id: process.env.PYLON_CLIENT_ID,
      client_secret: process.env.PYLON_CLIENT_SECRET,
    }),
  });

  const data = await response.json();
  cachedToken = data.access_token;
  // Refresh slightly early to avoid edge-of-expiry failures.
  tokenExpiresAt = Date.now() + (data.expires_in - 60) * 1000;
  return cachedToken;
}

async function makeGraphQLRequest(query, variables) {
  const token = await getAccessToken();

  const response = await fetch("https://pylon.mortgage/graphql", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({ query, variables }),
  });

  return response.json();
}

Error responses

Unauthenticated requests return:
{
  "errors": [
    {
      "message": "Unauthorized",
      "extensions": {
        "code": "UNAUTHENTICATED"
      }
    }
  ]
}

Best practices

  1. Store credentials securely - Never expose your client secret or tokens in client-side code
  2. Cache tokens and re-request before expiry - Reuse a cached token until it expires, then request a new one
  3. Handle errors gracefully - Surface authentication failures clearly
  4. Use HTTPS - Always use HTTPS in production
  5. Rotate credentials - Regularly rotate your client credentials for security