Skip to content

CRED Enterprise API Documentation

Commercial Data Platform – Integration Guide

1. Overview

The CRED Commercial Platform exposes a secure, high-availability GraphQL API designed for enterprise-scale data enrichment, identity resolution, and commercial intelligence workflows.

This guide provides an end-to-end implementation blueprint covering:

  • Authentication
  • API key lifecycle management
  • Filtering and search capabilities
  • Schema reference

This documentation is optimized for:

  • Platform engineering teams
  • Solution architects
  • Enterprise IT stakeholders

2. Environments

Environment Base URL Purpose
Production https://api.external.credplatform.com/graphql Live datasets, production workloads
Staging https://api-staging.external.credplatform.com/graphql Live datasets, staging rate limits for testing

All functionality is consistent across environments except dataset size and SLA guarantees.

3. Authentication & Access Control

The platform supports a two-step authentication model designed for enterprise governance.

3.1 User Authentication (Login)

First, authenticate with your credentials to obtain a JWT token.

Mutation:

mutation AuthenticateUser($input: AuthenticateUserInput!) {
  authenticateUser(input: $input) {
    token
  }
}

Variables:

{
  "input": {
    "email": "your.email@example.com",
    "password": "your_password"
  }
}

Response:

{
  "data": {
    "authenticateUser": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    }
  }
}

3.2 API Key Creation

Use the JWT token from authentication to create an API key.

HTTP Header:

Authorization: Bearer <JWT_TOKEN>

Mutation:

mutation CreateApiKey($input: CreateApiKeyInput!) {
  createApiKey(input: $input)
}

Note: The expiresInDays field is optional. If not specified, the API key is believed to default to 1 year (365 days) validity, though this could not be confirmed via the external API (see API Key Validity for details).

Variables:

{
  "input": {
    "name": "My API Key",
    "expiresInDays": 30
  }
}

Example without expiration (uses default 1 year):

{
  "input": {
    "name": "My API Key"
  }
}

Response:

{
  "data": {
    "createApiKey": "cred_xxxxx..."
  }
}

API Key Security

API keys are shown only once — store securely.

4. Authorization for API Requests

Endpoint: POST /graphql

HTTP

Authorization: Bearer cred_<YOUR_API_KEY>
Content-Type: application/json

5. Filter Fields

Filter Syntax

Every filter field takes a list of filter objects, each shaped as:

{ values: [ ... ], comparison: IS_ANY_OF }
  • comparison is an enum (SearchComparisonType) — see Comparison Operators. Because filters are supplied via a GraphQL variable (see below), comparison is written as a JSON string ("IS_ANY_OF").
  • values is always a list, even for a single value.

Important — passing filters. Filters must be supplied as a GraphQL variable named exactly searchFilters (likewise topMarkets / officeLocation for companies). Inline object literals written directly in the query fail at the upstream service (400 Bad Request / INTERNAL_SERVER_ERROR) — the gateway applies its filter transformation only when the variable name is exactly searchFilters. This was confirmed against staging on 2026-06-29; see the verified shapes in Section 6.

Use these fields in searchFilters:

Comparison Operators

  • IS_ANY_OF - Matches any of the provided values (default for inclusion filters)
  • IS_NOT_ANY_OF - Excludes any of the provided values
  • IS_ALL_OF - Matches all of the provided values
  • BETWEEN - Matches values within a range (requires 2 values)
  • MORE_THAN - Greater than
  • MORE_OR_EQUALS_THAN - Greater than or equal to
  • LESS_THAN - Less than
  • LESS_OR_EQUALS_THAN - Less than or equal to

Note — boolean fields. For boolean filters (isExclusive, isEstimate), use IS_ANY_OF. The SearchComparisonType enum also defines a bare IS member, but the examples in this guide standardize on IS_ANY_OF for consistency with every other filter.

Pagination

All connection queries use cursor-based pagination. There is no first or limit argument — page size is controlled by the server (Staging returns 1 result per call).

Each response includes:

  • totalCount — total number of matching records
  • edges[].cursor — the cursor for that individual record
  • pageInfo.hasNextPage — whether more results exist
  • pageInfo.endCursor — the cursor to request the next page

To fetch the next page, pass the previous response's endCursor into the after argument:

query Companies($searchFilters: InputCompanySearchFilters, $after: String) {
  companiesConnection(after: $after, searchFilters: $searchFilters) {
    edges {
      cursor
      node { id name }
    }
    pageInfo { hasNextPage endCursor }
  }
}

Variables:

{
  "after": "PREVIOUS_END_CURSOR",
  "searchFilters": {
    "keywords": [{ "values": ["software"], "comparison": "IS_ANY_OF" }]
  }
}

Person Filters (InputPersonsSearchFilters)

Identity:

  • identity - Search by name or role
  • name - Search by full name

Demographics:

  • age - Filter by age range
  • birthDate - Filter by birth date
  • gender - Filter by gender

Location:

  • location - Filter by location
  • country - Filter by country
  • regionId - Filter by region ID

Salary:

  • salary - Filter by salary (maps to grossSalary)
  • grossSalary - Filter by gross salary
  • netSalary - Filter by net salary

Skills & Education:

  • skills - Filter by skills
  • educationLevel - Filter by education level

Other:

  • languageIds - Filter by language IDs

Company Connection Filters

searchFilters (InputCompanySearchFilters)

  • keywords - Text-based search across company data (filter list; values are strings, e.g. ["software development"])
  • country - Filter by country (accepts country names or IDs: ["United States", "USA"] or [234])
  • headquarters - Filter by headquarters location (accepts location names or IDs: ["Silicon Valley"] or [234])
  • industry - Filter by industry. values are Industry enum members (e.g. Accounting, Aerospace___Defense, AI___Machine_Learning_Services), not free-text like "IT". Query the Industry enum via introspection for the full list (415 members).
  • location - Filter by location (accepts location names or IDs: ["New York"] or [234])
  • region - Filter by region (accepts region names or IDs: ["California"] or [1])
  • numberOfEmployees - Filter by number of employees (integer)
  • employeeCount - Filter by number of employees - friendly name (integer, can be used with BETWEEN)
  • revenue - Filter by revenue (integer, can be used with BETWEEN)

topMarkets

Filter companies by their top markets (regions where they operate). Accepts region names (e.g., ["United States", "France"]). Uses IS_ANY_OF (default) or IS_NOT_ANY_OF comparison.

officeLocation

Filter companies by office locations (regions where they have offices). Accepts region names (e.g., ["United States", "France"]). Uses IS_ANY_OF (default) or IS_NOT_ANY_OF comparison.

Note: Both topMarkets and officeLocation accept region names as strings, which are automatically converted to internal region IDs. The comparison field is optional and defaults to IS_ANY_OF if not specified.

Deal Connection Filters

searchFilters (InputDealSearchFilters)

Deal Identification:

  • id - Filter by deal ID (string)
  • title - Filter by deal title (string search)
  • type - Filter by deal type. values are DealType enum members: SPONSORSHIP, MEDIA, FULL_DEAL, RELATIONSHIP.
  • status - Filter by deal status. values are DealStatus enum members: ACTIVE, PAST, FUTURE.

Dates & Duration:

  • announcedDate - Filter by announcement date (date range)
  • startDate - Filter by start date (date range)
  • endDate - Filter by end date (date range)
  • dealLength - Filter by deal length/duration (integer range)

Financial:

  • annualValue - Filter by annual value (integer range)
  • totalValue - Filter by total value (integer range)
  • isEstimate - Filter by whether the value is estimated (boolean)

Deal Terms:

  • isExclusive - Filter by exclusivity (boolean)
  • renewalOption - Filter by renewal option type. values are DealRenewalOptionType enum members: NEW, CONFIRMED, RENEWAL.

Buyer Company Filters:

  • buyerCompanyIds - Filter by buyer company IDs (integer range)
  • buyerCompanyKeywords - Filter by buyer company keywords (string)
  • buyerCompanyNormalizedKeywords - Filter by buyer company normalized keywords (string)
  • buyerCompanyCategoryId - Filter by buyer company category ID (integer)
  • buyerCompanyRegionId - Filter by buyer company region ID (integer)
  • buyerCompanyRevenue - Filter by buyer company revenue (big integer range)
  • buyerNormalizedIndustryId - Filter by buyer normalized industry ID (string)
  • buyerParentCompanyId - Filter by buyer parent company ID (integer)

Seller Company Filters:

  • sellerCompanyIds - Filter by seller company IDs (integer range)
  • sellerCompanyKeywords - Filter by seller company keywords (string)
  • sellerCompanyNormalizedKeywords - Filter by seller company normalized keywords (string)
  • sellerCompanyCategoryId - Filter by seller company category ID (integer)
  • sellerCompanyRegionId - Filter by seller company region ID (integer)
  • sellerNormalizedIndustryId - Filter by seller normalized industry ID (string)
  • sellerParentCompanyId - Filter by seller parent company ID (integer)

Persons & Sports:

  • sellerPersonIds - Filter by seller person IDs (integer range)
  • sportId - Filter by sport ID (integer range)

sorters

Sort deal results by field in ascending (ASC) or descending (DESC) order.

Note — sorters uses [JSONObject!] intentionally (confirmed via introspection). Unlike searchFilters, which must be passed as a typed variable for gateway filter-transformation to work, the gateway does not expose a dedicated sorter input type in the current schema version. sorters therefore accepts a generic JSON object list (e.g. [{ "field": "announcedDate", "direction": "DESC" }]). The searchFilters-variable-name constraint described in the filter-syntax section does not apply to sorters.

6. Examples

Filters are passed as GraphQL variables — the inline object-literal form fails at the upstream service (see the verification note at the top of this guide). Each example below shows the query and its accompanying Variables block.

query Persons($searchFilters: InputPersonsSearchFilters) {
  personsConnection(searchFilters: $searchFilters) {
    edges {
      node {
        id
        name
        firstName
        lastName
        skills
        gender
        categoryIds
        age
        languages {
          id
          name
        }
        identifiers {
          name
          value
        }
        salary {
          grossSalary {
            value
            currency
            multiplier
            isVerified
            localCurrency
            localCurrencyValue
            localCurrencyValueMultiplier
          }
          grossSalaryLowerRange {
            value
            currency
            multiplier
            isVerified
            localCurrency
            localCurrencyValue
            localCurrencyValueMultiplier
          }
          grossSalaryUpperRange {
            value
            currency
            multiplier
            isVerified
            localCurrency
            localCurrencyValue
            localCurrencyValueMultiplier
          }
        }
      }
      cursor
    }
    totalCount
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}

Variables:

{
  "searchFilters": {
    "identity": [{ "values": ["John"], "comparison": "IS_ANY_OF" }],
    "gender": [{ "values": ["MALE", "FEMALE"], "comparison": "IS_ANY_OF" }],
    "skills": [{ "values": ["JavaScript", "TypeScript"], "comparison": "IS_ANY_OF" }],
    "educationLevel": [{ "values": ["POSTGRADUATE_MASTERS", "PHD"], "comparison": "IS_ANY_OF" }],
    "salary": [{ "values": [50000000, 500000000], "comparison": "BETWEEN" }]
  }
}

Retrieving Contact Data (Email)

query ContactExample {
  contactsConnection {
    totalCount
    edges {
      cursor
      node {
        id
        name
        firstName
        lastName
        email
        emails
        company { id name }
        person { id name }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}
query Companies(
  $topMarkets: [InputTopMarketsFilter!]
  $officeLocation: [InputOfficeLocationFilter!]
  $searchFilters: InputCompanySearchFilters
) {
  companiesConnection(
    topMarkets: $topMarkets
    officeLocation: $officeLocation
    searchFilters: $searchFilters
  ) {
    edges {
      node {
        id
        name
        websiteUrl
        parentCompanyId
        isPublic
        hasSubsidiary
        imageUrl
        marketCap {
          value
          currency
          multiplier
          isVerified
          localCurrency
          localCurrencyValue
          localCurrencyValueMultiplier
        }
        marketingBudget {
          value
          currency
          multiplier
          isVerified
          localCurrency
          localCurrencyValue
          localCurrencyValueMultiplier
        }
        fundingRaised {
          value
          currency
          multiplier
          isVerified
          localCurrency
          localCurrencyValue
          localCurrencyValueMultiplier
        }
        revenue {
          value
          currency
          multiplier
          isVerified
          localCurrency
          localCurrencyValue
          localCurrencyValueMultiplier
        }
        industry {
          id
          name
        }
        sector {
          id
          name
        }
        country {
          id
          name
          imageUrl
          alpha1Code
          alpha2Code
          alpha3Code
        }
        headquarters
        description
        ticker
        exchange
        foundedYear
        lastFundingDate
        numberOfEmployees
      }
    }
  }
}

Variables:

{
  "topMarkets": [{ "values": ["United States", "Canada"], "comparison": "IS_ANY_OF" }],
  "officeLocation": [{ "values": ["China"], "comparison": "IS_NOT_ANY_OF" }],
  "searchFilters": {
    "keywords": [{ "values": ["software development"], "comparison": "IS_ANY_OF" }],
    "revenue": [{ "values": [1000000000, 5000000000], "comparison": "BETWEEN" }],
    "employeeCount": [{ "values": [100, 1000], "comparison": "BETWEEN" }],
    "industry": [{ "values": ["AI___Machine_Learning_Services"], "comparison": "IS_ANY_OF" }],
    "country": [{ "values": ["United States"], "comparison": "IS_ANY_OF" }]
  }
}

industry values are Industry enum members (not free text). keywords is a filter list, not a bare string. The searchFilters portion above is confirmed working against staging (a query filtering industry: AI___Machine_Learning_Services returned live company data, e.g. Amazon).

Unverified: topMarkets / officeLocation with region names returned userCompanyId is required from the locale service for the API-key principal on staging, so region-name → region-ID resolution could not be confirmed end-to-end in this session. The arguments themselves are valid schema (InputTopMarketsFilter / InputOfficeLocationFilter, comparison of type InclusionComparisonType = IS_ANY_OF / IS_NOT_ANY_OF).

query Deals($searchFilters: InputDealSearchFilters, $sorters: [JSONObject!]) {
  dealsConnection(searchFilters: $searchFilters, sorters: $sorters) {
    edges {
      node {
        id
        title
        description
        type
        sponsorType
        announcedDate
        announcedDateSource
        startDate
        startDateSource
        endDate
        isEstimate
        isExclusive
        renewalOption
        totalDigitalImpressions
        annualValue {
          value
          currency
          multiplier
          isVerified
          localCurrency
          localCurrencyValue
          localCurrencyValueMultiplier
        }
        totalValue {
          value
          currency
          multiplier
          isVerified
          localCurrency
          localCurrencyValue
          localCurrencyValueMultiplier
        }
        buyerCompanies {
          id
          name
        }
        buyerCompanyIds
        buyerCompanyNames
        sellerCompanies {
          id
          name
        }
        sellerCompanyIds
        sellerCompanyNames
        sellerPersonIds
        sponsoredPersons {
          id
          name
        }
        sports {
          id
          name
        }
      }
      cursor
    }
    totalCount
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}

Variables:

{
  "searchFilters": {
    "type": [{ "values": ["SPONSORSHIP", "MEDIA"], "comparison": "IS_ANY_OF" }],
    "status": [{ "values": ["ACTIVE"], "comparison": "IS_ANY_OF" }],
    "annualValue": [{ "values": [1000000, 10000000], "comparison": "BETWEEN" }],
    "isExclusive": [{ "values": [true], "comparison": "IS_ANY_OF" }],
    "buyerCompanyKeywords": [{ "values": ["Nike", "Adidas"], "comparison": "IS_ANY_OF" }]
  },
  "sorters": [{ "field": "announcedDate", "direction": "DESC" }]
}

Note: type and status values are enum members — DealType is SPONSORSHIP / MEDIA / FULL_DEAL / RELATIONSHIP (there is no ENDORSEMENT), and DealStatus is ACTIVE / PAST / FUTURE.

Unverified: The full combined payload above (multiple searchFilters plus sorters) returned a transient 502 Bad Gateway from the deals upstream on staging during testing and could not be confirmed end-to-end. The variable form itself is confirmed working for dealsConnection — a searchFilters variable filtering on type: SPONSORSHIP returned live data (totalCount 478,881). The sorters argument is typed [JSONObject!] in the schema (confirmed via introspection), but its runtime behavior and the date format/range fields (announcedDate etc.) were not verifiable in this session.

contactsConnection is also available. It uses a different argument shape from the other connections:

  • filters: InputGetContactFilters
  • personSearchFilters: JSONObject
  • sortBy: ContactSortBy, personSortBy: PersonOrderBy, sortOrder: SortOrder
  • after: String (pagination)

personSearchFilters typing note: Unlike personsConnection which exposes InputPersonsSearchFilters, the contactsConnection argument personSearchFilters has no dedicated typed input schema and is typed as a bare JSONObject scalar (confirmed via introspection). The gateway does not apply the same searchFilters variable-name transformation here. Because it is an untyped JSONObject passthrough, its accepted shape is not enforced by the schema and has not been verified end-to-end; for person-style filtering prefer the typed filters: InputGetContactFilters argument.

The filters argument (InputGetContactFilters) exposes ID/email/query-style fields rather than the nested { values, comparison } filter objects used elsewhere. Confirmed fields include:

  • contactIds, personIds, companyIds, noCompanyIds, opportunityIds, userId, importId, collectionId — lists of Int
  • emailString
  • queryString (free-text search)
  • filterTypeContactFilterType enum
  • matchingStatus — list of EntityMatchingStatus enum
  • syncSourceType — list of SyncSourceType enum
  • syncSourceNameWithSyncIssues — list of ImportSourceTypeEnum
  • fromCreatedAt, toCreatedAt, fromUpdatedAt, toUpdatedAtTimestamp
  • updatedInLastHoursFloat
  • isContact, isCrm, hasSyncIssues, onlyInCollections, isDeleted, includeBlacklistedBoolean

7. GraphQL Playground

Creating API Keys

{
  "Authorization": "Bearer <CRED_JWT_TOKEN>"
}

Running Queries

{
  "Authorization": "Bearer cred_<YOUR_API_KEY>"
}

8. API Schema Reference

8.1 Company Object

Field Description
id Unique company ID
name Name of the company
imageUrl Logo or brand image
websiteUrl Public website
description Corporate description
headquarters HQ location
ticker Stock ticker symbol
exchange Exchange code
foundedYear Founding year
lastFundingDate Date of last funding round
isPublic Public/private flag
hasSubsidiary Subsidiary flag
parentCompanyId Parent entity ID
numberOfEmployees Number of employees
industry.id Industry identifier
industry.name Industry name
sector.id Sector identifier
sector.name Sector name
country.id Country identifier
country.name Country name
country.imageUrl Country flag image URL
country.alpha1Code ISO 3166-1 alpha-1 code (e.g., "US")
country.alpha2Code ISO 3166-1 alpha-2 code
country.alpha3Code ISO 3166-1 alpha-3 code (e.g., "USA")
revenue.value Revenue value
revenue.currency Currency code
revenue.multiplier Value multiplier (e.g., "MILLIONS")
revenue.isVerified Whether the value is verified
revenue.localCurrency Local currency code
revenue.localCurrencyValue Value in local currency
revenue.localCurrencyValueMultiplier Local currency multiplier
marketCap Market capitalization (same structure as revenue)
marketingBudget Marketing budget (same structure as revenue)
fundingRaised Total funding raised (same structure as revenue)

8.2 Person Object

Field Description
id Person ID
firstName First name
lastName Last name
name Full name
gender Gender
age Age
skills List of skills
categoryIds Category identifiers
languages.id Language identifier
languages.name Language name
identifiers.name Identifier name (e.g., "LinkedIn", "Twitter")
identifiers.value Identifier value (URL or handle)
salary.grossSalary.value Gross salary value
salary.grossSalary.currency Currency code
salary.grossSalary.multiplier Value multiplier (e.g., "THOUSANDS")
salary.grossSalary.isVerified Whether the value is verified
salary.grossSalary.localCurrency Local currency code
salary.grossSalary.localCurrencyValue Value in local currency
salary.grossSalary.localCurrencyValueMultiplier Local currency multiplier
salary.grossSalaryLowerRange Lower range of gross salary (same structure as grossSalary)
salary.grossSalaryUpperRange Upper range of gross salary (same structure as grossSalary)

8.3 Deal Object

Field Description
id Unique deal ID (required)
title Deal title
description Deal description
type Deal type (e.g., sponsorship, endorsement)
sponsorType Type of sponsorship
announcedDate Date the deal was announced
announcedDateSource Source of the announced date
startDate Deal start date
startDateSource Source of the start date
endDate Deal end date
isEstimate Whether the value is an estimate
isExclusive Whether the deal is exclusive
renewalOption Renewal option type (e.g., AUTOMATIC, OPTIONAL)
totalDigitalImpressions Total digital impressions
annualValue.value Annual value amount
annualValue.currency Currency code
annualValue.multiplier Value multiplier (e.g., "MILLIONS")
annualValue.isVerified Whether the value is verified
annualValue.localCurrency Local currency code
annualValue.localCurrencyValue Value in local currency
annualValue.localCurrencyValueMultiplier Local currency multiplier
totalValue Total deal value (same structure as annualValue)
buyerCompanies List of buyer companies
buyerCompanies.id Buyer company ID
buyerCompanies.name Buyer company name
buyerCompanyIds Array of buyer company IDs
buyerCompanyNames Array of buyer company names
sellerCompanies List of seller companies
sellerCompanies.id Seller company ID
sellerCompanies.name Seller company name
sellerCompanyIds Array of seller company IDs
sellerCompanyNames Array of seller company names
sellerPersonIds Array of seller person IDs
sponsoredPersons List of sponsored persons
sponsoredPersons.id Sponsored person ID
sponsoredPersons.name Sponsored person name
sports List of sports associated with the deal
sports.id Sport ID
sports.name Sport name

9. Error Handling

Authentication and rate-limit errors are returned by the gateway as HTTP errors with this body shape:

{ "message": "Invalid API key", "error": "Unauthorized", "statusCode": 401 }

Query-validation errors are returned in the standard GraphQL shape with an extensions.code:

{ "errors": [ { "message": "...", "extensions": { "code": "GRAPHQL_VALIDATION_FAILED" } } ] }
Scenario HTTP status error / code Resolution
Missing Authorization header 401 Unauthorized Send Authorization: Bearer <key>
Invalid/expired API key 401 Unauthorized (Invalid API key) Supply a valid API key
Invalid/expired JWT 401 Unauthorized (Invalid token: ...) Re-authenticate via authenticateUser
Invalid GraphQL query 400 GRAPHQL_VALIDATION_FAILED Fix the query/syntax
Rate limit exceeded 429 Too Many Requests Lower request frequency

10. Rate Limiting & Governance

API Key Validity

Limit Type Policy
Default key validity 1 year / 365 days (if expiresInDays is not specified when creating the API key)
Custom validity Can be set via expiresInDays when creating the API key, up to a maximum of 365 days (1 year)

Unverified: The external API exposes no query for listing or inspecting created API keys, and the schema does not surface a default value for the optional expiresInDays field (CreateApiKeyInput.expiresInDays is a plain optional Int). The 365-day default could therefore not be confirmed via the external API in this session.

Rate Limits by Environment

Environment Policy
Production • Non-data queries & mutations: 100 requests per 60 seconds (per IP and per user)
• Data connection queries (personsConnection, companiesConnection, dealsConnection, contactsConnection): 10 calls per day
• Results returned per data query: 1 result per call (use pageInfo.endCursor as the after variable in successive calls to page through additional results)
Staging • Non-data calls (queries and mutations): 100 requests per 60 seconds
• Data query results per call: 1 search result per call
• Data query daily limit: 10 calls per day

Exceeding a limit returns HTTP 429.

11. Security & Compliance

  • Keys have prefix cred_ and are user-scoped
  • JWTs use strict expiration
  • API keys must be stored in secret vaults
  • Production requires TLS
  • Full audit logs for key activity