Integration guide for the CRED Commercial Platform's GraphQL API, covering authentication, API key management, filtering, and schema reference.
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": "[email protected]",
"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
expiresInDaysfield is optional. If not specified, the API key defaults to 1 year (365 days) validity (see Rate Limiting & Governance 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..."
}
}!!! warning "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/json5. Filter Fields
Filter Syntax
Every filter field takes a list of filter objects, each shaped as:
{ values: [ ... ], comparison: IS_ANY_OF }comparisonis an enum (SearchComparisonType) — see Comparison Operators. Because filters are supplied via a GraphQL variable (see below),comparisonis written as a JSON string ("IS_ANY_OF").valuesis always a list, even for a single value.
Important — passing filters. Filters must be supplied as a GraphQL variable named exactly
searchFilters(likewisetopMarkets/officeLocationfor 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 exactlysearchFilters. 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 valuesIS_ALL_OF- Matches all of the provided valuesBETWEEN- Matches values within a range (requires 2 values)MORE_THAN- Greater thanMORE_OR_EQUALS_THAN- Greater than or equal toLESS_THAN- Less thanLESS_OR_EQUALS_THAN- Less than or equal to
Note — boolean fields. For boolean filters (
isExclusive,isEstimate), useIS_ANY_OF. TheSearchComparisonTypeenum also defines a bareISmember, but the examples in this guide standardize onIS_ANY_OFfor 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 recordsedges[].cursor— the cursor for that individual recordpageInfo.hasNextPage— whether more results existpageInfo.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)
InputPersonsSearchFilters)Identity:
identity- Search by name or rolename- Search by full name
Demographics:
age- Filter by age rangebirthDate- Filter by birth dategender- Filter by gender
Location:
location- Filter by locationcountry- Filter by countryregionId- Filter by region ID
Salary:
salary- Filter by salary (maps to grossSalary)grossSalary- Filter by gross salarynetSalary- Filter by net salary
Skills & Education:
skills- Filter by skillseducationLevel- Filter by education level
Other:
languageIds- Filter by language IDs
Company Connection Filters
searchFilters (InputCompanySearchFilters)
searchFilters (InputCompanySearchFilters)keywords- Text-based search across company data (filter list;valuesare 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.valuesareIndustryenum members (e.g.Accounting,Aerospace___Defense,AI___Machine_Learning_Services), not free-text like"IT". Query theIndustryenum 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 withBETWEEN)revenue- Filter by revenue (integer, can be used withBETWEEN)
topMarkets
topMarketsFilter 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
officeLocationFilter 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
topMarketsandofficeLocationaccept region names as strings, which are automatically converted to internal region IDs. Thecomparisonfield is optional and defaults toIS_ANY_OFif not specified.
Deal Connection Filters
searchFilters (InputDealSearchFilters)
searchFilters (InputDealSearchFilters)Deal Identification:
id- Filter by deal ID (string)title- Filter by deal title (string search)type- Filter by deal type.valuesareDealTypeenum members:SPONSORSHIP,MEDIA,FULL_DEAL,RELATIONSHIP.status- Filter by deal status.valuesareDealStatusenum 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.valuesareDealRenewalOptionTypeenum 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
sortersSort deal results by field in ascending (ASC) or descending (DESC) order.
Note —
sortersuses[JSONObject!]intentionally (confirmed via introspection). UnlikesearchFilters, 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.sorterstherefore accepts a generic JSON object list (e.g.[{ "field": "announcedDate", "direction": "DESC" }]). ThesearchFilters-variable-name constraint described in the filter-syntax section does not apply tosorters.
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.
Person Search
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 }
}
}Company Search
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" }]
}
}
industryvalues areIndustryenum members (not free text).keywordsis a filter list, not a bare string. ThesearchFiltersportion above is confirmed working against staging (a query filteringindustry: AI___Machine_Learning_Servicesreturned live company data, e.g. Amazon).Unverified:
topMarkets/officeLocationwith region names returneduserCompanyId is requiredfrom 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,comparisonof typeInclusionComparisonType=IS_ANY_OF/IS_NOT_ANY_OF).
Deal Search
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:
typeandstatusvalues are enum members —DealTypeisSPONSORSHIP/MEDIA/FULL_DEAL/RELATIONSHIP(there is noENDORSEMENT), andDealStatusisACTIVE/PAST/FUTURE.Unverified: The full combined payload above (multiple
searchFiltersplussorters) returned a transient502 Bad Gatewayfrom the deals upstream on staging during testing and could not be confirmed end-to-end. The variable form itself is confirmed working fordealsConnection— asearchFiltersvariable filtering ontype: SPONSORSHIPreturned live data (totalCount478,881). Thesortersargument is typed[JSONObject!]in the schema (confirmed via introspection), but its runtime behavior and the date format/range fields (announcedDateetc.) were not verifiable in this session.
Contact Search
contactsConnection is also available. It uses a different argument shape from the other connections:
filters: InputGetContactFilterspersonSearchFilters: JSONObjectsortBy: ContactSortBy,personSortBy: PersonOrderBy,sortOrder: SortOrderafter: String(pagination)
personSearchFilterstyping note: UnlikepersonsConnectionwhich exposesInputPersonsSearchFilters, thecontactsConnectionargumentpersonSearchFiltershas no dedicated typed input schema and is typed as a bareJSONObjectscalar (confirmed via introspection). The gateway does not apply the samesearchFiltersvariable-name transformation here. Because it is an untypedJSONObjectpassthrough, its accepted shape is not enforced by the schema and has not been verified end-to-end; for person-style filtering prefer the typedfilters: InputGetContactFiltersargument.
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 ofIntemail—Stringquery—String(free-text search)filterType—ContactFilterTypeenummatchingStatus— list ofEntityMatchingStatusenumsyncSourceType— list ofSyncSourceTypeenumsyncSourceNameWithSyncIssues— list ofImportSourceTypeEnumfromCreatedAt,toCreatedAt,fromUpdatedAt,toUpdatedAt—TimestampupdatedInLastHours—FloatisContact,isCrm,hasSyncIssues,onlyInCollections,isDeleted,includeBlacklisted—Boolean
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
expiresInDaysfield (CreateApiKeyInput.expiresInDaysis a plain optionalInt). 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
