Eagle API Documentation

Eagle Partner API

Everything you need to connect to Eagle and read or write data for your integration. Authenticate once, then call our GraphQL endpoint to access contacts, properties, addresses, appraisals, and compliance checks — all scoped to the accounts your client has been granted access to.

JWT authentication Account-scoped access GraphQL — single endpoint Contacts • Properties • Compliance Checks
Token endpointExchange credentials for a session JWT.
POST /api/v3/partner_graphql/token
GraphQL endpointAll queries and mutations go here.
POST /api/v3/partner_graphql
Base URLPrefix all endpoint paths with this.
https://www.eagleagent.com.au

Getting started

The Eagle Partner API is a GraphQL API — you POST a JSON body containing a query string and variables, and receive a JSON response. Here are the three steps to connect:

  1. Receive your credentials. Eagle provisions your partner client with a client ID, client secret, and access to specific Eagle accounts. Contact Eagle support to get set up.
  2. Get a session token. POST /api/v3/partner_graphql/token with HTTP Basic auth. The response contains a JWT valid for 24 hours. See Get a token.
  3. Make GraphQL requests. POST /api/v3/partner_graphql with Authorization: Bearer <token> and an accountId on every query or mutation. See Make a request.
Account scoping: your token only authorises the Eagle accounts linked to your partner client. Supplying a different account ID will return an authorisation error.

Get a session token

Base64-encode CLIENT_ID:CLIENT_SECRET, then send a POST to the token endpoint with that value as a Basic auth header. No request body is needed.

Request

curl \
  -X POST \
  -H "Authorization: Basic BASE64_OF_CLIENT_ID_COLON_SECRET" \
  https://www.eagleagent.com.au/api/v3/partner_graphql/token

Response

{
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "expires_at": 1720000000
  }
}

How to Base64-encode your credentials

# macOS / Linux
echo -n "your_client_id:your_client_secret" | base64

# PowerShell
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("your_client_id:your_client_secret"))
Cache the token for its full 24-hour lifetime. Re-request a new token only when it expires — do not request a fresh token on every API call.
Invalid credentials return HTTP 401 with { "errors": [{ "message": "Invalid credentials" }] }.

Make a GraphQL request

POST JSON to /api/v3/partner_graphql with Authorization: Bearer TOKEN. The body must contain a query field and an optional variables map. Include accountId inside your variables on every query or mutation.

Request format

curl \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  --data '{"query": "query Ping { partnerPing }", "variables": {}}' \
  https://www.eagleagent.com.au/api/v3/partner_graphql

Response

{ "data": { "partnerPing": "pong" } }

Request body fields

FieldTypeRequiredDescription
queryStringYesThe GraphQL query or mutation string.
variablesObjectNoKey/value map of variables referenced in the query.
operationNameStringNoSelects a named operation when the query string defines multiple operations.
Use partnerPing as a lightweight connectivity and token-validity check before running real queries.

Pagination

All list queries use cursor-based pagination. Pass first for the page size and after for the cursor. Read pageInfo from each response to determine whether more pages exist.

Field / argumentTypeDescription
firstIntRecords per page. Maximum 50.
afterStringCursor from the previous pageInfo.endCursor. Omit on the first page.
pageInfo.hasNextPageBooleantrue when more records are available.
pageInfo.endCursorStringPass as after to load the next page.

Example

query ListContacts($accountId: ID!, $first: Int!, $after: String) {
  contacts(accountId: $accountId, first: $first, after: $after) {
    nodes { id firstName lastName email }
    pageInfo { hasNextPage endCursor }
  }
}

First page:

{ "accountId": "123", "first": 25 }

Next page — use endCursor from the response above:

{ "accountId": "123", "first": 25, "after": "eyJpZCI6Mn0" }

Connectivity queries

Use these before running real queries to confirm your token and account access are working.

partnerPing

Returns "pong". Requires only a valid JWT — no accountId needed.

Query

query {
  partnerPing
}

Response

{ "data": { "partnerPing": "pong" } }

partnerPermissionProbe

Returns true if your client is authorised on the given account.

Query

query Probe($accountId: ID!) {
  partnerPermissionProbe(
    accountId: $accountId
  )
}

Variables

{ "accountId": "123" }

Contacts

🔒 Requires contacts:read

Query contacts for an authorised account. Supports listing with pagination and fetching a single contact by ID.

Query arguments

ArgumentTypeRequiredDescription
accountIdIDYesThe Eagle account to query.
firstIntYes (list)Page size, max 50.
afterStringNoPagination cursor.
ids[ID]NoFilter to specific contact IDs.
queryStringNoText search across name, email, and phone.
emailStringNoExact email address filter.
idIDYes (single)Required for the single-record contact query.

Contact object fields

FieldTypeDescription
idID!Unique contact ID.
firstNameString!First name.
lastNameStringLast name.
fullNameStringCombined first and last name.
emailStringPrimary email. Use emails { address } for all addresses.
mobilePhoneStringMobile number.
businessHoursPhoneStringBusiness hours phone.
afterHoursPhoneStringAfter hours phone.
companyStringCompany name.
suburbStringSuburb.
stateStringState.
postcodeStringPostcode (plain string on contacts).
countryStringCountry.
legalNameStringLegal name.
dateOfBirthISO8601DateTimeDate of birth.
backgroundInfoStringFree-text background notes.
doNotContactBooleantrue if contact should not be contacted.
unsubscribedFromAllBooleantrue if unsubscribed from all communications.
createdAtISO8601DateTime!Record creation timestamp.
updatedAtISO8601DateTime!Last update timestamp.

List contacts

query GetContacts($accountId: ID!, $first: Int!, $after: String, $query: String, $email: String) {
  contacts(accountId: $accountId, first: $first, after: $after, query: $query, email: $email) {
    nodes {
      id
      firstName
      lastName
      email
      mobilePhone
      suburb
      state
    }
    pageInfo { hasNextPage endCursor }
  }
}
{ "accountId": "123", "first": 25 }

Get a single contact

query GetContact($accountId: ID!, $id: ID!) {
  contact(accountId: $accountId, id: $id) {
    id
    firstName
    lastName
    fullName
    email
    mobilePhone
    company
    suburb
    state
    postcode
    legalName
    createdAt
    updatedAt
  }
}
{ "accountId": "123", "id": "456" }

Properties

🔒 Requires properties:read

Query property listings for an authorised account.

Query arguments

ArgumentTypeRequiredDescription
accountIdIDYesThe Eagle account to query.
firstIntYes (list)Page size, max 50.
afterStringNoPagination cursor.
ids[ID]NoFilter to specific property IDs.
status[String]NoFilter by listing status, e.g. ["Current", "Sold"].
queryStringNoSearch by address text.
idIDYes (single)Required for the single-record property query.

Property object fields

FieldTypeDescription
idID!Unique property ID.
formattedAddressString!Full formatted address — easiest way to display the address.
unitStringUnit number.
streetNoStringStreet number.
streetStringStreet name.
lotNoStringLot number.
postcodePostcodeTypeNested object. Use ... on PostcodeAustralia { suburb state postcode }.
countryStringCountry.
statusPropertyStatusEnum!Listing status: Current, Sold, Withdrawn, etc.
saleOrLeaseSaleOrLeaseEnumWhether for sale or lease.
bedroomsIntBedrooms.
bathroomsIntBathrooms.
landSizeStringLand size value.
landSizeUnitsStringUnits, e.g. sqm.
latitudeFloatLatitude.
longitudeFloatLongitude.
listedAtISO8601DateTimeWhen the property was listed.
soldDateStringDate sold (if applicable).
thumbnailSquareString300×300 thumbnail image URL.
agencyReferenceStringAgency internal reference number.

List properties

query GetProperties($accountId: ID!, $first: Int!, $after: String, $status: [String!]) {
  properties(accountId: $accountId, first: $first, after: $after, status: $status) {
    nodes {
      id
      formattedAddress
      status
      saleOrLease
      bedrooms
      bathrooms
      postcode {
        ... on PostcodeAustralia { suburb state postcode }
        ... on PostcodeNewZealand { suburb postcode }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}
{ "accountId": "123", "first": 25, "status": ["Current"] }

Get a single property

query GetProperty($accountId: ID!, $id: ID!) {
  property(accountId: $accountId, id: $id) {
    id
    formattedAddress
    unit
    streetNo
    street
    postcode { ... on PostcodeAustralia { suburb state postcode } }
    status
    bedrooms
    bathrooms
    landSize
    landSizeUnits
    latitude
    longitude
    listedAt
    thumbnailSquare
  }
}
{ "accountId": "123", "id": "789" }

Addresses

🔒 Requires addresses:read

Address records are physical locations in Eagle, separate from active property listings.

Query arguments

ArgumentTypeRequiredDescription
accountIdIDYesThe Eagle account to query.
firstIntYes (list)Page size, max 50.
afterStringNoPagination cursor.
ids[ID]NoFilter to specific address IDs.
queryStringNoSearch by address text.
idIDYes (single)Required for the single-record address query.

Address object fields

FieldTypeDescription
idID!Unique address ID.
formattedAddressStringStreet line (unit, number, street name).
formattedFullAddressStringFull address including suburb, state, and postcode.
unitStringUnit number.
streetNoStringStreet number.
streetStringStreet name.
lotNoStringLot number.
postcodePostcodeTypeNested postcode object with suburb, state, postcode fields.
countryStringCountry.
bedroomsIntBedrooms.
bathroomsIntBathrooms.
landSizeStringLand size value.
landSizeUnitsStringUnits for land size.

Example

query GetAddresses($accountId: ID!, $first: Int!, $after: String, $query: String) {
  addresses(accountId: $accountId, first: $first, after: $after, query: $query) {
    nodes {
      id
      formattedFullAddress
      bedrooms
      bathrooms
      postcode { ... on PostcodeAustralia { suburb state postcode } }
    }
    pageInfo { hasNextPage endCursor }
  }
}
{ "accountId": "123", "first": 25 }

Appraisals

🔒 Requires appraisals:read

Query appraisal records for an authorised account.

Query arguments

ArgumentTypeRequiredDescription
accountIdIDYesThe Eagle account to query.
firstIntYes (list)Page size, max 50.
afterStringNoPagination cursor.
ids[ID]NoFilter to specific appraisal IDs.
status[String]NoFilter by appraisal status.
queryStringNoSearch by address text.
idIDYes (single)Required for the single-record appraisal query.

Appraisal object fields

FieldTypeDescription
idID!Unique appraisal ID.
formattedAddressString!Full formatted address.
unitStringUnit number.
streetNoStringStreet number.
streetStringStreet name.
lotNoStringLot number.
postcodePostcodeTypeNested postcode with suburb, state, postcode.
statusAppraisalStatusEnumAppraisal status.
listingTypeListingTypeEnumListing type (residential, commercial, etc.).
saleOrRentSaleOrRentEnumFor sale or rent.
bedroomsIntBedrooms.
bathroomsIntBathrooms.
landSizeFloatLand size.
landSizeUnitsLandSizeUnitsEnumUnits for land size.
appraisalDateISO8601DateTime!Date of appraisal.
createdAtISO8601DateTime!Record creation timestamp.
updatedAtISO8601DateTime!Last update timestamp.

Example

query GetAppraisals($accountId: ID!, $first: Int!, $after: String) {
  appraisals(accountId: $accountId, first: $first, after: $after) {
    nodes {
      id
      formattedAddress
      status
      saleOrRent
      bedrooms
      bathrooms
      appraisalDate
      postcode { ... on PostcodeAustralia { suburb state postcode } }
    }
    pageInfo { hasNextPage endCursor }
  }
}
{ "accountId": "123", "first": 25 }

Compliance Checks (AML)

🔒 Requires aml:read + Compliance Checks feature

Compliance checks (internally called AML checks) let you read identity-verification records associated with contacts. The GraphQL field names use the amlCheck prefix. The Compliance Checks feature must be enabled on the target account.

Query arguments — amlChecks (list)

ArgumentTypeRequiredDescription
accountIdIDYesThe Eagle account to query.
firstIntYesPage size, max 50.
afterStringNoPagination cursor.
contactIdIDNoFilter to checks for a specific contact.
statusAmlCheckStatusEnumNoFilter by status. Values: IN_PROGRESS, COMPLETED, FAILED, ARCHIVED.
propertyIdIDNoFilter to checks linked to a specific property.

Query arguments — amlCheck (single)

ArgumentTypeRequiredDescription
accountIdIDYesThe Eagle account to query.
idIDYesThe compliance check ID to retrieve.

AmlCheck object fields

FieldTypeDescription
idID!Unique compliance check ID.
statusStringCurrent status (title case): In Progress, Completed, Failed, Archived.
sourceString!Set to your partner client name when created via Partner API; Eagle for in-app checks. Immutable.
partnerApiClientIdIDYour partner client ID, set automatically at creation. Immutable.
noteStringFree-text note.
contactIdID!Associated contact ID.
contactTypeString!Role of the contact in the transaction: seller or buyer. Defaults to seller.
entityTypeString!Entity being verified: individual, joint_individuals, company, trust, charity, or estate. Defaults to individual.
portalUrlStringURL to your AML partner's verification portal for this check, if applicable.
externalIdStringYour system's identifier for this check (e.g. from your AML provider). Optional; set at creation and can be updated later.
accountIdIDAssociated Eagle account ID.
officeIdIDAssociated office ID (if set).
officeOfficeAssociated office object. Query office { id name email phone } for the office contact details.
userIdIDID of the Eagle agent the check is attributed to (its creator, if set).
userUserThe Eagle agent the check is attributed to. Query user { id email firstName lastName } for the agent's email. Null for checks created via the Partner API (no in-app agent).
createdAtISO8601DateTime!Creation timestamp.
updatedAtISO8601DateTime!Last update timestamp.
statusUpdatedAtISO8601DateTimeWhen the status was last changed.
contactContactFull contact object (see Contacts schema).
attachments[AmlAttachment!]!Files linked to this check. Each has id, fileName, downloadUrl, status, createdAt.
properties[Property!]!Property listings linked to this check.
appraisals[Appraisal!]!Appraisals linked to this check.
Immutable fields: source and partnerApiClientId are automatically set at creation from your authenticated partner client — you cannot supply or change them. Store these from the create response if you need them later.

List compliance checks

query GetAmlChecks($accountId: ID!, $first: Int!, $after: String, $status: AmlCheckStatusEnum) {
  amlChecks(accountId: $accountId, first: $first, after: $after, status: $status) {
    nodes {
      id
      status
      note
      source
      partnerApiClientId
      contactType
      entityType
      portalUrl
      externalId
      createdAt
      updatedAt
      contact { id firstName lastName email }
      attachments { id fileName downloadUrl }
    }
    pageInfo { hasNextPage endCursor }
  }
}
{ "accountId": "123", "first": 25, "status": "IN_PROGRESS" }

Get a single compliance check

query GetAmlCheck($accountId: ID!, $id: ID!) {
  amlCheck(accountId: $accountId, id: $id) {
    id
    status
    note
    source
    partnerApiClientId
    contactType
    entityType
    portalUrl
    externalId
    createdAt
    updatedAt
    statusUpdatedAt
    contact { id firstName lastName email }
    attachments { id fileName downloadUrl status }
    properties { id formattedAddress status }
    appraisals  { id formattedAddress status }
  }
}
{ "accountId": "123", "id": "1001" }

Get the transaction context (agency, office & agent)

A common need when processing an AML notification is the Agency ID (Eagle account), the Office ID, and the agent's email so the check can be assigned to the right person. All three are already available on the amlCheck in a single query — no extra calls required. The agent is exposed via the user field, and their email is at user.email.

query GetAmlCheckContext($accountId: ID!, $id: ID!) {
  amlCheck(accountId: $accountId, id: $id) {
    id
    externalId
    status

    # Agency ID (Eagle account)
    accountId

    # Office ID + contact details
    office {
      id
      name
      email
      phone
    }

    # The agent the check is attributed to — includes their email
    user {
      id
      email
      firstName
      lastName
      office { id name }
    }
  }
}
{ "accountId": "123", "id": "1001" }

Example response

{
  "data": {
    "amlCheck": {
      "id": "1001",
      "externalId": "ext-55",
      "status": "In Progress",
      "accountId": "123",
      "office": {
        "id": "7",
        "name": "West Coast Property Sales",
        "email": "[email protected]",
        "phone": "+61 8 9000 0000"
      },
      "user": {
        "id": "42",
        "email": "[email protected]",
        "firstName": "Alex",
        "lastName": "Agent",
        "office": { "id": "7", "name": "West Coast Property Sales" }
      }
    }
  }
}
user is the agent the check is attributed to. Checks created by an Eagle agent in-app already have user populated; checks created via the Partner API have no in-app agent, so user will be null.

Compliance Check Mutations (AML)

🔒 Requires aml:write + Compliance Checks feature

Write operations for compliance checks. All mutations accept an input object and return both an amlCheck payload and an errors array. Always check errors, even when the HTTP status is 200.

Create a compliance check — createAmlCheck

Creates a new compliance check for a contact. Use this first when starting a new compliance workflow.

Input arguments

ArgumentTypeRequiredDescription
accountIdIDYesAuthorised account ID.
contactIdIDYesContact this check belongs to. Must exist in the account.
contactTypeStringNoRole in the transaction: seller or buyer. Defaults to seller. Case-insensitive.
entityTypeStringNoEntity being verified: individual, joint_individuals, company, trust, charity, or estate. Defaults to individual.
portalUrlStringNoURL to your AML partner's verification portal for this check.
externalIdStringNoYour system's identifier for this check (e.g. from your AML provider).
statusStringNoInitial status. Defaults to In Progress if omitted.
officeIdIDNoOffice to associate with this check.
noteStringNoFree-text note or source reference.
propertyIds[ID]NoProperty IDs to link at creation.
appraisalIds[ID]NoAppraisal IDs to link at creation.
attachments[String]NoFile URLs to attach immediately.

Mutation

mutation CreateCheck(
  $accountId: ID!,  $contactId: ID!,  $contactType: String,  $entityType: String,
  $portalUrl: String,  $externalId: String,  $status: String,  $officeId: ID,  $note: String,
  $propertyIds: [ID!],  $appraisalIds: [ID!],  $attachments: [String!]
) {
  createAmlCheck(input: {
    accountId: $accountId,  contactId: $contactId,
    contactType: $contactType,  entityType: $entityType,  portalUrl: $portalUrl,
    externalId: $externalId,  status: $status,  officeId: $officeId,  note: $note,
    propertyIds: $propertyIds,  appraisalIds: $appraisalIds,  attachments: $attachments
  }) {
    amlCheck {
      id
      status
      source
      partnerApiClientId
      contactType
      entityType
      portalUrl
      externalId
      note
    }
    errors
  }
}

Variables

{
  "accountId": "123",
  "contactId": "456",
  "contactType": "seller",
  "entityType": "individual",
  "portalUrl": "https://aml-partner.example.com/verify/abc123",
  "externalId": "partner-check-abc123",
  "note": "Passport provided by applicant",
  "propertyIds": ["789"]
}

Response

{
  "data": {
    "createAmlCheck": {
      "amlCheck": {
        "id": "1001",
        "status": "In Progress",
        "source": "Your Partner Client Name",
        "partnerApiClientId": "42",
        "contactType": "seller",
        "entityType": "individual",
        "portalUrl": "https://aml-partner.example.com/verify/abc123",
        "externalId": "partner-check-abc123",
        "note": "Passport provided by applicant"
      },
      "errors": []
    }
  }
}
  • source is automatically set to your partner client name — you cannot supply or change it.
  • If contactId is not found in the account, errors will contain "Contact not found".
  • Invalid property or appraisal IDs are silently skipped.

Update a compliance check — updateAmlCheck

Updates the note, officeId, contactId, contactType, entityType, portalUrl, or externalId. Only provided fields are changed.

Input arguments

ArgumentTypeRequiredDescription
accountIdIDYesAuthorised account ID.
idIDYesCompliance check ID to update.
noteStringNoUpdated note text.
officeIdIDNoUpdated office association.
contactIdIDNoReassign to a different contact (must exist in the same account).
contactTypeStringNoUpdated role: seller or buyer. Case-insensitive.
entityTypeStringNoUpdated entity type: individual, joint_individuals, company, trust, charity, or estate.
portalUrlStringNoUpdated AML partner portal URL.
externalIdStringNoUpdated external identifier for this check.

Mutation

mutation UpdateCheck(
  $accountId: ID!, $id: ID!, $note: String, $officeId: ID, $contactId: ID,
  $contactType: String, $entityType: String, $portalUrl: String, $externalId: String
) {
  updateAmlCheck(input: {
    accountId: $accountId,  id: $id,  note: $note,
    officeId: $officeId,    contactId: $contactId,
    contactType: $contactType,  entityType: $entityType,  portalUrl: $portalUrl,
    externalId: $externalId
  }) {
    amlCheck { id status note contactType entityType portalUrl externalId updatedAt }
    errors
  }
}

Variables

{ "accountId": "123", "id": "1001", "note": "Driver licence also verified on 2024-06-01" }

Response

{
  "data": {
    "updateAmlCheck": {
      "amlCheck": {
        "id": "1001", "status": "In Progress",
        "note": "Driver licence also verified on 2024-06-01",
        "contactType": "seller",
        "entityType": "individual",
        "portalUrl": "https://aml-partner.example.com/verify/abc123",
        "externalId": "partner-check-abc123",
        "updatedAt": "2024-06-01T10:00:00Z"
      },
      "errors": []
    }
  }
}

Update check status — updateAmlCheckStatus

Changes only the status of a check without touching other fields.

Input arguments

ArgumentTypeRequiredDescription
accountIdIDYesAuthorised account ID.
idIDYesCompliance check ID.
statusAmlCheckStatusEnum!YesNew status: IN_PROGRESS, COMPLETED, FAILED, or ARCHIVED.

Mutation

mutation UpdateStatus($accountId: ID!, $id: ID!, $status: AmlCheckStatusEnum!) {
  updateAmlCheckStatus(input: {
    accountId: $accountId,  id: $id,  status: $status
  }) {
    amlCheck { id status statusUpdatedAt }
    errors
  }
}

Variables

{ "accountId": "123", "id": "1001", "status": "COMPLETED" }

Response

{
  "data": {
    "updateAmlCheckStatus": {
      "amlCheck": {
        "id": "1001", "status": "Completed",
        "statusUpdatedAt": "2024-06-01T12:00:00Z"
      },
      "errors": []
    }
  }
}
Status values are sent as UPPER_SNAKE_CASE (e.g. IN_PROGRESS) but returned in title case (e.g. InProgress).

Attach files — attachFilesToAmlCheck

Adds one or more file URLs to an existing check. Does not remove existing attachments.

Input arguments

ArgumentTypeRequiredDescription
accountIdIDYesAuthorised account ID.
idIDYesCompliance check ID.
urls[String!]!YesPublicly accessible file URLs to attach.

Mutation

mutation AttachFiles($accountId: ID!, $id: ID!, $urls: [String!]!) {
  attachFilesToAmlCheck(input: {
    accountId: $accountId,  id: $id,  urls: $urls
  }) {
    amlCheck {
      id
      attachments { id fileName downloadUrl status }
    }
    errors
  }
}

Variables

{
  "accountId": "123",
  "id": "1001",
  "urls": [
    "https://storage.example.com/passport-scan.pdf",
    "https://storage.example.com/drivers-licence.pdf"
  ]
}

Response

{
  "data": {
    "attachFilesToAmlCheck": {
      "amlCheck": {
        "id": "1001",
        "attachments": [
          { "id": "201", "fileName": "passport-scan.pdf",   "downloadUrl": "https://...", "status": "uploaded" },
          { "id": "202", "fileName": "drivers-licence.pdf", "downloadUrl": "https://...", "status": "uploaded" }
        ]
      },
      "errors": []
    }
  }
}
Blank or empty URL strings are silently ignored.

Remove a file — destroyAmlAttachment

Permanently removes a single attachment. Returns the updated check with remaining attachments.

Input arguments

ArgumentTypeRequiredDescription
accountIdIDYesAuthorised account ID.
attachmentIdIDYesID from attachments { id } on the check.

Mutation

mutation RemoveFile($accountId: ID!, $attachmentId: ID!) {
  destroyAmlAttachment(input: {
    accountId: $accountId,  attachmentId: $attachmentId
  }) {
    amlCheck {
      id
      attachments { id fileName downloadUrl }
    }
    errors
  }
}

Variables

{ "accountId": "123", "attachmentId": "201" }

Response

{
  "data": {
    "destroyAmlAttachment": {
      "amlCheck": {
        "id": "1001",
        "attachments": [
          { "id": "202", "fileName": "drivers-licence.pdf", "downloadUrl": "https://..." }
        ]
      },
      "errors": []
    }
  }
}
If the attachment ID doesn't exist, or belongs to a check in a different account, you receive Attachment not found in errors.

Update listing associations — updateAmlCheckListingAssociations

Replaces the property and/or appraisal links on a check. Providing propertyIds replaces all existing property links. Providing appraisalIds replaces all existing appraisal links. Omitting a key leaves those links unchanged.

Input arguments

ArgumentTypeRequiredDescription
accountIdIDYesAuthorised account ID.
idIDYesCompliance check ID.
propertyIds[ID]NoReplacement list of property IDs. Pass [] to remove all property links.
appraisalIds[ID]NoReplacement list of appraisal IDs. Pass [] to remove all appraisal links.

Mutation

mutation UpdateAssociations(
  $accountId: ID!, $id: ID!,
  $propertyIds: [ID!], $appraisalIds: [ID!]
) {
  updateAmlCheckListingAssociations(input: {
    accountId: $accountId,    id: $id,
    propertyIds: $propertyIds, appraisalIds: $appraisalIds
  }) {
    amlCheck {
      id
      status
      properties { id formattedAddress }
      appraisals  { id formattedAddress }
    }
    errors
  }
}

Variables

{ "accountId": "123", "id": "1001", "propertyIds": ["789", "790"] }
Settled listing restriction: properties in a settled/sold state cannot be associated. Supplying a settled property ID returns an error such as Cannot associate with settled listings (Property IDs: 789).

Webhooks

Register a single HTTPS endpoint and Eagle will POST a signed JSON payload whenever a compliance-check event occurs across any account linked to your partner client. No per-account setup is required.

All webhook mutations require the aml:write permission and a valid partner JWT. The optional accountIds argument on registerWebhook lets you validate that specific accounts are linked to your client, but the subscription itself is always global — every linked account will deliver events to your endpoint.

Supported event types

Event typeWhen it fires
aml_check.createdA new compliance check is created.
aml_check.updatedA compliance check's note or other fields are updated.
aml_check.status_changedA compliance check's status changes.

Payload shape

Each delivery sends a POST with Content-Type: application/json and the following headers:

HeaderDescription
X-Eagle-Signaturesha256=<HMAC-SHA256 hex digest> of the raw request body, signed with your subscription's signing secret.
X-Eagle-EventThe event type string, e.g. aml_check.created.
X-Eagle-DeliveryA unique UUID for this delivery attempt.

Verifying the signature

Always verify X-Eagle-Signature before processing a payload. Compute sha256=HMAC-SHA256(signingSecret, rawRequestBody) and compare it to the header value using a constant-time comparison to prevent timing attacks.

# Ruby example
expected = "sha256=" + OpenSSL::HMAC.hexdigest("SHA256", signing_secret, request.raw_post)
secure   = ActiveSupport::SecurityUtils.secure_compare(expected, request.headers["X-Eagle-Signature"])
return head(:unauthorized) unless secure

# Node.js example
const crypto = require("crypto");
const expected = "sha256=" + crypto.createHmac("sha256", signingSecret).update(rawBody).digest("hex");
const received = req.headers["x-eagle-signature"];
const valid    = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
if (!valid) return res.status(401).send("Invalid signature");

Register webhook — registerWebhook

Creates a webhook subscription for your partner client. One URL per partner client — all linked accounts will send events to this endpoint. Calling this mutation again with the same URL is idempotent and returns the existing subscription.

Input arguments

ArgumentTypeRequiredDescription
urlStringYesHTTPS endpoint that will receive webhook payloads.
eventTypes[String]YesOne or more event types to subscribe to.
accountIds[ID]NoOptional list of account IDs to validate access. The subscription covers all linked accounts regardless.

Mutation

mutation RegisterWebhook($url: String!, $eventTypes: [String!]!) {
  registerWebhook(input: {
    url: $url,
    eventTypes: $eventTypes
  }) {
    subscription {
      id
      url
      eventTypes
      enabled
    }
    signingSecret
    errors
  }
}

Variables

{
  "url": "https://your-server.example.com/eagle/webhooks",
  "eventTypes": ["aml_check.created", "aml_check.status_changed"]
}

Response

{
  "data": {
    "registerWebhook": {
      "subscription": {
        "id": "1",
        "url": "https://your-server.example.com/eagle/webhooks",
        "eventTypes": ["aml_check.created", "aml_check.status_changed"],
        "enabled": true
      },
      "signingSecret": "a3f8...c2d1",
      "errors": []
    }
  }
}
Store the signingSecret securely — it is only returned at registration time and on secret rotation. Use it to verify the X-Eagle-Signature header on every incoming request.

Update webhook — updateWebhook

Updates the URL, event types, and/or enabled state of an existing subscription.

Input arguments

ArgumentTypeRequiredDescription
idIDYesWebhook subscription ID.
urlStringNoNew HTTPS endpoint URL.
eventTypes[String]NoReplacement list of event types. Omit to leave unchanged.
enabledBooleanNoEnable or disable deliveries.

Mutation

mutation UpdateWebhook($id: ID!, $url: String, $eventTypes: [String!], $enabled: Boolean) {
  updateWebhook(input: {
    id: $id,
    url: $url,
    eventTypes: $eventTypes,
    enabled: $enabled
  }) {
    subscription {
      id
      url
      eventTypes
      enabled
    }
    errors
  }
}

Variables

{ "id": "1", "enabled": false }

Delete webhook — deleteWebhook

Permanently removes a webhook subscription. Deliveries in flight may still be attempted.

Input arguments

ArgumentTypeRequiredDescription
idIDYesWebhook subscription ID.

Mutation

mutation DeleteWebhook($id: ID!) {
  deleteWebhook(input: { id: $id }) {
    errors
  }
}

Variables

{ "id": "1" }

Rotate signing secret — rotateWebhookSecret

Generates a new signing secret for a subscription. The old secret is immediately invalidated. Update your server to use the new secret before rotating.

Input arguments

ArgumentTypeRequiredDescription
idIDYesWebhook subscription ID.

Mutation

mutation RotateWebhookSecret($id: ID!) {
  rotateWebhookSecret(input: { id: $id }) {
    signingSecret
    errors
  }
}

Variables

{ "id": "1" }

Error handling

Errors appear in two places: a top-level errors array for request-level failures, and a per-mutation errors array inside the response payload for business-logic failures. Always handle both.

Top-level GraphQL errors

Error messageCause & fix
Account <id> is not authorized for this clientThe accountId is not linked to your partner client. Use only accounts provisioned for you.
Not authorized for contacts:read (or any permission key)Your client does not hold the required permission. Contact Eagle support.
AML checks feature is not enabled for this accountCompliance Checks must be enabled on the account by the account holder.
HTTP 401 UnauthorizedToken is missing, expired, or invalid. Re-authenticate via the token endpoint.

Mutation payload errors

Error messageMutation(s)
Contact not foundcreateAmlCheck, updateAmlCheck
AML check not foundupdateAmlCheck, updateAmlCheckStatus, attachFilesToAmlCheck, updateAmlCheckListingAssociations
Attachment not founddestroyAmlAttachment
Cannot associate with settled listings (Property IDs: ...)updateAmlCheckListingAssociations, createAmlCheck
Could not create AML checkcreateAmlCheck
Could not update AML checkupdateAmlCheck
Could not update AML check statusupdateAmlCheckStatus
Could not attach files to AML checkattachFilesToAmlCheck
Could not remove attachmentdestroyAmlAttachment

Error response shape

{
  "data": {
    "createAmlCheck": {
      "amlCheck": null,
      "errors": ["Contact not found"]
    }
  }
}
Single-record queries (contact, property, address, appraisal, amlCheck) return null when the record is not found in the scoped account — no top-level error is raised.

Quick reference

  • Get a token via POST /api/v3/partner_graphql/token with HTTP Basic auth. Tokens last 24 hours.
  • Send all operations to POST /api/v3/partner_graphql with Authorization: Bearer TOKEN.
  • Include accountId on every query and mutation — it must be linked to your client.
  • Use partnerPing to test connectivity without loading data.
  • List queries are paginated: use first + after, max 50 records per page.
  • For mutations, always check the errors array even on HTTP 200.
  • Store source and partnerApiClientId from compliance check create responses — they cannot be changed later.
  • Do not link compliance checks to properties with a settled/sold status.
  • Compliance status enum: send UPPER_SNAKE_CASE, receive title case.

Resources

Standard Eagle GraphQL API (agent credentials, full schema):

Eagle GraphQL API documentation →

Postman collection — import, set client_id, client_secret, and account_id, then run Get Partner Token:

Eagle_Partner_GraphQL.postman_collection.json ↓

Eagle Partner API documentation