Is there a reliable way to check pending agreement status for multiple App Store Connect accounts via API?

Hey everyone,

I'm managing CI/CD pipelines for around 45 iOS apps across different Apple Developer accounts. One recurring pain point is blocked pipelines due to unsigned agreements. Things like the Paid Applications Agreement and the Apple Developer Program License Agreement. I built an internal dashboard to flag these before they block a release, but I'm hitting a wall with detection accuracy.

Since there's no dedicated endpoint for agreement status, I'm running three probes per account and checking for 403 FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED:

  • GET /v1/agreements
  • GET /v1/bundleIds?filter[identifier]={bundleId}&filter[platform]=IOS
  • GET /v1/certificates?limit=1

Case 1 : Works perfectly. Account has "Apple Developer Program License Agreement has been updated and needs to be reviewed" : All three endpoint return 403 (In this case, the step 1 is enough)

#  Step 1  /v1/agreements            →  HTTP 403  ⛔ BLOCKED
#  Step 2  /v1/bundleIds             →  HTTP 403  ⛔ BLOCKED
#  Step 3  /v1/certificates          →  HTTP 403  ⛔ BLOCKED

# [Step 1 body]
{
  "errors": [
    {
      "id": "TXF6QUVS6OY66YVUNINVLKXZFA",
      "status": "403",
      "code": "FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED",
      "title": "A required agreement is missing or has expired.",
      "detail": "This request requires an in-effect agreement that has not been signed or has expired.",
      "links": {
        "see": "/business"
      }
    }
  ]
}

# [Step 2 body]
{
  "errors": [
    {
      "id": "MTDI5P37UTYQOOVJSMXCWUK42U",
      "status": "403",
      "code": "FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED",
      "title": "A required agreement is missing or has expired.",
      "detail": "This request requires an in-effect agreement that has not been signed or has expired.",
      "links": {
        "see": "/business"
      }
    }
  ]
}

# [Step 3 body]
{
  "errors": [
    {
      "id": "GI6EN2CMBFJIJJZM547LSW66KY",
      "status": "403",
      "code": "FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED",
      "title": "A required agreement is missing or has expired.",
      "detail": "This request requires an in-effect agreement that has not been signed or has expired.",
      "links": {
        "see": "/business"
      }
    }
  ]
}

Case 2 : Not detected. Different account, same message in App Store Connect UI. But v1/agreements endpoint return 404 while other 2 steps return 200

#  Step 1  /v1/agreements            →  HTTP 404  ➖ 404
#  Step 2  /v1/bundleIds             →  HTTP 200  ✅ OK
#  Step 3  /v1/certificates          →  HTTP 200  ✅ OK

# [Step 1 body]
{
  "errors": [
    {
      "id": "37459578-8167-449c-ad22-e0ffa392df2d",
      "status": "404",
      "code": "NOT_FOUND",
      "title": "The specified resource does not exist",
      "detail": "The path provided does not match a defined resource type."
    }
  ]
}

# [Step 2 body]
{
  "data": [
    {
      "type": "bundleIds",
      "id": "xxx",
      "attributes": {
        "identifier": "xxx"
      },
      "links": {
        "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/[xxx]"
      }
    }
  ],
  "links": {
    "self": "https://api.appstoreconnect.apple.com/v1/bundleIds?fields%5BbundleIds%5D=identifier&filter%5Bplatform%5D=IOS&filter%5Bidentifier%5D=[xxx]&limit=1"
  },
  "meta": {
    "paging": {
      "total": 1,
      "limit": 1
    }
  }
}

# [Step 3 body]
{
  "data": [
    {
      "type": "certificates",
      "id": "xxx",
      "attributes": {
        "serialNumber": "xxx",
        "expirationDate": "2026-07-03T04:47:09.000+00:00",
        "certificateType": "DISTRIBUTION"
      },
      "links": {
        "self": "https://api.appstoreconnect.apple.com/v1/certificates/[xxx]"
      }
    }
  ],
  "links": {
    "self": "https://api.appstoreconnect.apple.com/v1/certificates?fields%5Bcertificates%5D=serialNumber%2CcertificateType%2CexpirationDate&limit=1",
    "next": "https://api.appstoreconnect.apple.com/v1/certificates?fields%5Bcertificates%5D=serialNumber%2CcertificateType%2CexpirationDate&cursor=[xxx]&limit=1"
  },
  "meta": {
    "paging": {
      "total": 4,
      "limit": 1
    }
  }
}

Same agreement type, same UI warning, completely different API behaviour. My best guess is Apple enforces the agreement deadline progressively. The 403 gate only kicks in once the deadline is crossed or the account reaches a certain state, while the UI warning shows much earlier.

What I'm looking for, Is there a supported API endpoint that reflects pending agreement status regardless of enforcement state? Or is the 403 gate genuinely the only signal available and some pending agreements just won't show up until Apple enforces them?

Happy to hear "there's no API for this" if that's the reality. Just want to make sure I'm not missing something before I accept that limitation.

Thanks.

Is there a reliable way to check pending agreement status for multiple App Store Connect accounts via API?
 
 
Q