API reference

Requests

Access requests: the link a client opens to grant your agency access to their accounts, and the progress of each requested service.

Create a request

POST /requests

Creates an access request for a client and returns its inviteUrl (to send or link to) and embedUrl (to show in an iframe). No email is sent unless sendEmail is true. Each request counts once toward your monthly access link allowance (prospects separately); at an enforced limit you get 403 PLAN_LIMIT_REACHED, and with overage billing extra client links are billed instead. Request at least one service or the intake form.

Scope requests:create Requires Idempotency-Key

Headers

  • Idempotency-Key string required

    A unique value per create, such as a UUID (1-255 visible ASCII characters). Retrying with the same key and body returns the original result instead of creating another object; keys are kept for 24 hours.

Body

  • clientId string required

    The client to request access from.

  • requestedServices object

    Services to request, keyed by service ID (see GET /services).

    Show fields of requestedServices
    • accessLevel string

      One of the service's role values; leave out for services without roles.

    • optional boolean

      The client may skip it. The request completes once each service is granted, or skipped if optional. Default false.

    • requestedAccountLinks array of object

      Which of your connected accounts (see GET /accounts) the client grants access to. Each must be one of your accounts on the service's platform.

      Show fields of requestedAccountLinks
      • internalAccountId string required
      • googleAdsMccAccountId string

        Required for Google Ads MCC.

      • metaBusinessManagerId string
  • intakeForm object

    Ask the client to fill in your intake form (it must be enabled with questions).

    Show fields of intakeForm
    • requested boolean required
  • sendEmail boolean

    Email the client the link. Default false.

  • thankYouMessage string

    Up to 2000 characters.

  • redirectUrl string

    An absolute http(s) URL to send the client to after finishing. Up to 2048 characters.

  • expiresAt datetime

    A future time, at most a year away, after which the client can no longer grant access. Without it the request never expires.

Returns

201 The new request.

Fields (object)
  • id uuid
  • clientId uuid
  • externalClientId string | null
  • status string

    pending: nothing granted, skipped or submitted yet (opening the link or signing in does not change it). in_progress: at least one service is granted or skipped, an invite awaits your confirmation, or the intake form is submitted. completed: every service is granted (optional ones may be skipped instead), not every service was skipped, and the intake form, if requested, is submitted. A completed request returns to in_progress if you ask for more access. cancelled and expired are final. One of pending, in_progress, completed, cancelled, expired.

  • stateVersion integer

    Increases with every change; use it to ignore older states and events.

  • source string

    Where the request was created. One of api, dashboard, static_link.

  • inviteUrl string

    The link the client opens to grant access.

  • embedUrl string

    The same link for an iframe in your portal.

  • intakeForm object
    Show fields of intakeForm
    • requested boolean
    • complete boolean
  • services array of object
    Show fields of services
    • service string

      The service ID, such as Google Ads.

    • platform string

      The platform, such as Google.

    • accessLevel string | null

      The requested role.

    • optional boolean

      The client may skip it. Optional services still need to be granted or skipped for the request to complete.

    • status string

      Only optional services can be skipped. One of pending, granted, skipped.

    • accounts array of object

      Your accounts access is requested for.

      Show fields of accounts
      • internalAccountId string
      • googleAdsMccAccountId string | null
      • metaBusinessManagerId string | null
    • grantedAssets array of object

      The client's assets access was granted to.

      Show fields of grantedAssets
      • id string

        The asset's ID on the platform.

      • name string | null
      • accessLevel string | null
  • thankYouMessage string | null
  • redirectUrl string | null

    Where the client is sent after finishing.

  • createdAt datetime
  • completedAt datetime | null
  • expiresAt datetime | null

    After this, no new grants; the request reports expired unless it is already completed or cancelled. Null when the request never expires.

  • cancelledAt datetime | null
  • 400 The request is invalid (VALIDATION_FAILED); details lists the problems, with field when one applies.
  • 401 The API key is missing, invalid or revoked.
  • 403 The key lacks the scope (CAPABILITY_REQUIRED), the plan has no API access (PLAN_NOT_ENTITLED), or, when creating a request, the monthly limit is reached (PLAN_LIMIT_REACHED).
  • 404 Not found, or it belongs to another agency.
  • 409 A conflict: an externalClientId in use or immutable, an Idempotency-Key reused with a different body or still in progress, or a request in a state that does not allow this.
  • 429 Rate limited (RATE_LIMITED); wait for Retry-After seconds.
Request
curl -X POST "https://api.agencyaccess.co/api/v2/requests" \
  -H "Authorization: Bearer $AGENCYACCESS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "clientId": "7c1e9f52-3b8a-4d2e-9a61-5f0c2d8b4e17",
  "requestedServices": {
    "Google Ads": {
      "accessLevel": "ADMIN",
      "requestedAccountLinks": [
        {
          "internalAccountId": "Xk7pQ2mR9vT4wB8nC3dF6hJ1"
        }
      ]
    },
    "Meta Ads": {
      "accessLevel": "['ADVERTISE', 'ANALYZE']",
      "optional": true,
      "requestedAccountLinks": [
        {
          "internalAccountId": "Lm5sZ8aE2gH6jK9qN3rU7yW4"
        }
      ]
    }
  },
  "intakeForm": {
    "requested": true
  },
  "redirectUrl": "https://portal.example.com/onboarding/done"
}
JSON
Response 201
{
  "data": {
    "id": "2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
    "clientId": "7c1e9f52-3b8a-4d2e-9a61-5f0c2d8b4e17",
    "externalClientId": "crm-4821",
    "status": "pending",
    "stateVersion": 1,
    "source": "api",
    "inviteUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
    "embedUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72?mode=embed",
    "intakeForm": {
      "requested": true,
      "complete": false
    },
    "services": [
      {
        "service": "Google Ads",
        "platform": "Google",
        "accessLevel": "ADMIN",
        "optional": false,
        "status": "pending",
        "accounts": [
          {
            "internalAccountId": "Xk7pQ2mR9vT4wB8nC3dF6hJ1",
            "googleAdsMccAccountId": null,
            "metaBusinessManagerId": null
          }
        ],
        "grantedAssets": []
      },
      {
        "service": "Meta Ads",
        "platform": "Meta",
        "accessLevel": "['ADVERTISE', 'ANALYZE']",
        "optional": true,
        "status": "pending",
        "accounts": [
          {
            "internalAccountId": "Lm5sZ8aE2gH6jK9qN3rU7yW4",
            "googleAdsMccAccountId": null,
            "metaBusinessManagerId": null
          }
        ],
        "grantedAssets": []
      }
    ],
    "thankYouMessage": null,
    "redirectUrl": "https://portal.example.com/onboarding/done",
    "createdAt": "2026-10-07T09:15:02.000Z",
    "completedAt": null,
    "expiresAt": "2026-10-21T09:15:02.000Z",
    "cancelledAt": null
  },
  "meta": {
    "requestId": "req_1f0b6c2e9a7d4f58b3c1e6a9d2f4b7c0"
  }
}

List requests

GET /requests

Lists requests, oldest first. Demo requests are never returned.

Scope requests:read

Query parameters

  • limit integer

    Results per page, 1-100.

  • cursor string

    The meta.nextCursor of the previous page. Cursors only work with the filters they were issued for.

  • clientId uuid

    Only this client's requests.

  • externalClientId string

    Only requests of the client with this external ID.

  • status string

    Only requests with this status.

    One of pending, in_progress, completed, cancelled, expired.

Returns

200 A page of requests.

Fields of each item (object)
  • id uuid
  • clientId uuid
  • externalClientId string | null
  • status string

    pending: nothing granted, skipped or submitted yet (opening the link or signing in does not change it). in_progress: at least one service is granted or skipped, an invite awaits your confirmation, or the intake form is submitted. completed: every service is granted (optional ones may be skipped instead), not every service was skipped, and the intake form, if requested, is submitted. A completed request returns to in_progress if you ask for more access. cancelled and expired are final. One of pending, in_progress, completed, cancelled, expired.

  • stateVersion integer

    Increases with every change; use it to ignore older states and events.

  • source string

    Where the request was created. One of api, dashboard, static_link.

  • inviteUrl string

    The link the client opens to grant access.

  • embedUrl string

    The same link for an iframe in your portal.

  • intakeForm object
    Show fields of intakeForm
    • requested boolean
    • complete boolean
  • services array of object
    Show fields of services
    • service string

      The service ID, such as Google Ads.

    • platform string

      The platform, such as Google.

    • accessLevel string | null

      The requested role.

    • optional boolean

      The client may skip it. Optional services still need to be granted or skipped for the request to complete.

    • status string

      Only optional services can be skipped. One of pending, granted, skipped.

    • accounts array of object

      Your accounts access is requested for.

      Show fields of accounts
      • internalAccountId string
      • googleAdsMccAccountId string | null
      • metaBusinessManagerId string | null
    • grantedAssets array of object

      The client's assets access was granted to.

      Show fields of grantedAssets
      • id string

        The asset's ID on the platform.

      • name string | null
      • accessLevel string | null
  • thankYouMessage string | null
  • redirectUrl string | null

    Where the client is sent after finishing.

  • createdAt datetime
  • completedAt datetime | null
  • expiresAt datetime | null

    After this, no new grants; the request reports expired unless it is already completed or cancelled. Null when the request never expires.

  • cancelledAt datetime | null
  • 400 The request is invalid (VALIDATION_FAILED); details lists the problems, with field when one applies.
  • 401 The API key is missing, invalid or revoked.
  • 403 The key lacks the scope (CAPABILITY_REQUIRED), the plan has no API access (PLAN_NOT_ENTITLED), or, when creating a request, the monthly limit is reached (PLAN_LIMIT_REACHED).
  • 429 Rate limited (RATE_LIMITED); wait for Retry-After seconds.
Request
curl "https://api.agencyaccess.co/api/v2/requests?externalClientId=crm-4821" \
  -H "Authorization: Bearer $AGENCYACCESS_API_KEY"
Response 200
{
  "data": [
    {
      "id": "2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
      "clientId": "7c1e9f52-3b8a-4d2e-9a61-5f0c2d8b4e17",
      "externalClientId": "crm-4821",
      "status": "in_progress",
      "stateVersion": 4,
      "source": "api",
      "inviteUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
      "embedUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72?mode=embed",
      "intakeForm": {
        "requested": true,
        "complete": false
      },
      "services": [
        {
          "service": "Google Ads",
          "platform": "Google",
          "accessLevel": "ADMIN",
          "optional": false,
          "status": "granted",
          "accounts": [
            {
              "internalAccountId": "Xk7pQ2mR9vT4wB8nC3dF6hJ1",
              "googleAdsMccAccountId": null,
              "metaBusinessManagerId": null
            }
          ],
          "grantedAssets": [
            {
              "id": "1234567890",
              "name": "1234567890",
              "accessLevel": "ADMIN"
            }
          ]
        },
        {
          "service": "Meta Ads",
          "platform": "Meta",
          "accessLevel": "['ADVERTISE', 'ANALYZE']",
          "optional": true,
          "status": "pending",
          "accounts": [
            {
              "internalAccountId": "Lm5sZ8aE2gH6jK9qN3rU7yW4",
              "googleAdsMccAccountId": null,
              "metaBusinessManagerId": null
            }
          ],
          "grantedAssets": []
        }
      ],
      "thankYouMessage": null,
      "redirectUrl": "https://portal.example.com/onboarding/done",
      "createdAt": "2026-10-07T09:15:02.000Z",
      "completedAt": null,
      "expiresAt": "2026-10-21T09:15:02.000Z",
      "cancelledAt": null
    }
  ],
  "meta": {
    "requestId": "req_1f0b6c2e9a7d4f58b3c1e6a9d2f4b7c0",
    "nextCursor": null
  }
}

Retrieve a request

GET /requests/{id}

Returns the request with the status of every requested service and the assets access was granted to. Compare stateVersion to tell newer states from older ones.

Scope requests:read

Path parameters

  • id uuid required

    The request ID.

Returns

200 The request.

Fields (object)
  • id uuid
  • clientId uuid
  • externalClientId string | null
  • status string

    pending: nothing granted, skipped or submitted yet (opening the link or signing in does not change it). in_progress: at least one service is granted or skipped, an invite awaits your confirmation, or the intake form is submitted. completed: every service is granted (optional ones may be skipped instead), not every service was skipped, and the intake form, if requested, is submitted. A completed request returns to in_progress if you ask for more access. cancelled and expired are final. One of pending, in_progress, completed, cancelled, expired.

  • stateVersion integer

    Increases with every change; use it to ignore older states and events.

  • source string

    Where the request was created. One of api, dashboard, static_link.

  • inviteUrl string

    The link the client opens to grant access.

  • embedUrl string

    The same link for an iframe in your portal.

  • intakeForm object
    Show fields of intakeForm
    • requested boolean
    • complete boolean
  • services array of object
    Show fields of services
    • service string

      The service ID, such as Google Ads.

    • platform string

      The platform, such as Google.

    • accessLevel string | null

      The requested role.

    • optional boolean

      The client may skip it. Optional services still need to be granted or skipped for the request to complete.

    • status string

      Only optional services can be skipped. One of pending, granted, skipped.

    • accounts array of object

      Your accounts access is requested for.

      Show fields of accounts
      • internalAccountId string
      • googleAdsMccAccountId string | null
      • metaBusinessManagerId string | null
    • grantedAssets array of object

      The client's assets access was granted to.

      Show fields of grantedAssets
      • id string

        The asset's ID on the platform.

      • name string | null
      • accessLevel string | null
  • thankYouMessage string | null
  • redirectUrl string | null

    Where the client is sent after finishing.

  • createdAt datetime
  • completedAt datetime | null
  • expiresAt datetime | null

    After this, no new grants; the request reports expired unless it is already completed or cancelled. Null when the request never expires.

  • cancelledAt datetime | null
  • 401 The API key is missing, invalid or revoked.
  • 403 The key lacks the scope (CAPABILITY_REQUIRED), the plan has no API access (PLAN_NOT_ENTITLED), or, when creating a request, the monthly limit is reached (PLAN_LIMIT_REACHED).
  • 404 Not found, or it belongs to another agency.
  • 429 Rate limited (RATE_LIMITED); wait for Retry-After seconds.
Request
curl "https://api.agencyaccess.co/api/v2/requests/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72" \
  -H "Authorization: Bearer $AGENCYACCESS_API_KEY"
Response 200
{
  "data": {
    "id": "2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
    "clientId": "7c1e9f52-3b8a-4d2e-9a61-5f0c2d8b4e17",
    "externalClientId": "crm-4821",
    "status": "in_progress",
    "stateVersion": 4,
    "source": "api",
    "inviteUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
    "embedUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72?mode=embed",
    "intakeForm": {
      "requested": true,
      "complete": false
    },
    "services": [
      {
        "service": "Google Ads",
        "platform": "Google",
        "accessLevel": "ADMIN",
        "optional": false,
        "status": "granted",
        "accounts": [
          {
            "internalAccountId": "Xk7pQ2mR9vT4wB8nC3dF6hJ1",
            "googleAdsMccAccountId": null,
            "metaBusinessManagerId": null
          }
        ],
        "grantedAssets": [
          {
            "id": "1234567890",
            "name": "1234567890",
            "accessLevel": "ADMIN"
          }
        ]
      },
      {
        "service": "Meta Ads",
        "platform": "Meta",
        "accessLevel": "['ADVERTISE', 'ANALYZE']",
        "optional": true,
        "status": "pending",
        "accounts": [
          {
            "internalAccountId": "Lm5sZ8aE2gH6jK9qN3rU7yW4",
            "googleAdsMccAccountId": null,
            "metaBusinessManagerId": null
          }
        ],
        "grantedAssets": []
      }
    ],
    "thankYouMessage": null,
    "redirectUrl": "https://portal.example.com/onboarding/done",
    "createdAt": "2026-10-07T09:15:02.000Z",
    "completedAt": null,
    "expiresAt": "2026-10-21T09:15:02.000Z",
    "cancelledAt": null
  },
  "meta": {
    "requestId": "req_1f0b6c2e9a7d4f58b3c1e6a9d2f4b7c0"
  }
}

Cancel a request

POST /requests/{id}/cancel

Stops a request: the client can no longer sign in or grant access through it, and no more reminders can be sent. Sign-ins the client had not finished using are discarded. Access already granted is not revoked. Cancelling a cancelled request is fine; completed or expired requests return 409 INVALID_STATE.

Scope requests:cancel

Path parameters

  • id uuid required

    The request ID.

Returns

200 The cancelled request.

Fields (object)
  • id uuid
  • clientId uuid
  • externalClientId string | null
  • status string

    pending: nothing granted, skipped or submitted yet (opening the link or signing in does not change it). in_progress: at least one service is granted or skipped, an invite awaits your confirmation, or the intake form is submitted. completed: every service is granted (optional ones may be skipped instead), not every service was skipped, and the intake form, if requested, is submitted. A completed request returns to in_progress if you ask for more access. cancelled and expired are final. One of pending, in_progress, completed, cancelled, expired.

  • stateVersion integer

    Increases with every change; use it to ignore older states and events.

  • source string

    Where the request was created. One of api, dashboard, static_link.

  • inviteUrl string

    The link the client opens to grant access.

  • embedUrl string

    The same link for an iframe in your portal.

  • intakeForm object
    Show fields of intakeForm
    • requested boolean
    • complete boolean
  • services array of object
    Show fields of services
    • service string

      The service ID, such as Google Ads.

    • platform string

      The platform, such as Google.

    • accessLevel string | null

      The requested role.

    • optional boolean

      The client may skip it. Optional services still need to be granted or skipped for the request to complete.

    • status string

      Only optional services can be skipped. One of pending, granted, skipped.

    • accounts array of object

      Your accounts access is requested for.

      Show fields of accounts
      • internalAccountId string
      • googleAdsMccAccountId string | null
      • metaBusinessManagerId string | null
    • grantedAssets array of object

      The client's assets access was granted to.

      Show fields of grantedAssets
      • id string

        The asset's ID on the platform.

      • name string | null
      • accessLevel string | null
  • thankYouMessage string | null
  • redirectUrl string | null

    Where the client is sent after finishing.

  • createdAt datetime
  • completedAt datetime | null
  • expiresAt datetime | null

    After this, no new grants; the request reports expired unless it is already completed or cancelled. Null when the request never expires.

  • cancelledAt datetime | null
  • 401 The API key is missing, invalid or revoked.
  • 403 The key lacks the scope (CAPABILITY_REQUIRED), the plan has no API access (PLAN_NOT_ENTITLED), or, when creating a request, the monthly limit is reached (PLAN_LIMIT_REACHED).
  • 404 Not found, or it belongs to another agency.
  • 409 A conflict: an externalClientId in use or immutable, an Idempotency-Key reused with a different body or still in progress, or a request in a state that does not allow this.
  • 429 Rate limited (RATE_LIMITED); wait for Retry-After seconds.
Request
curl -X POST "https://api.agencyaccess.co/api/v2/requests/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72/cancel" \
  -H "Authorization: Bearer $AGENCYACCESS_API_KEY"
Response 200
{
  "data": {
    "id": "2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
    "clientId": "7c1e9f52-3b8a-4d2e-9a61-5f0c2d8b4e17",
    "externalClientId": "crm-4821",
    "status": "cancelled",
    "stateVersion": 5,
    "source": "api",
    "inviteUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72",
    "embedUrl": "https://acme.agencyaccess.co/i/2f6d8a14-91c3-4b7e-a5d0-8e3f1c6b9a72?mode=embed",
    "intakeForm": {
      "requested": true,
      "complete": false
    },
    "services": [
      {
        "service": "Google Ads",
        "platform": "Google",
        "accessLevel": "ADMIN",
        "optional": false,
        "status": "granted",
        "accounts": [
          {
            "internalAccountId": "Xk7pQ2mR9vT4wB8nC3dF6hJ1",
            "googleAdsMccAccountId": null,
            "metaBusinessManagerId": null
          }
        ],
        "grantedAssets": [
          {
            "id": "1234567890",
            "name": "1234567890",
            "accessLevel": "ADMIN"
          }
        ]
      },
      {
        "service": "Meta Ads",
        "platform": "Meta",
        "accessLevel": "['ADVERTISE', 'ANALYZE']",
        "optional": true,
        "status": "pending",
        "accounts": [
          {
            "internalAccountId": "Lm5sZ8aE2gH6jK9qN3rU7yW4",
            "googleAdsMccAccountId": null,
            "metaBusinessManagerId": null
          }
        ],
        "grantedAssets": []
      }
    ],
    "thankYouMessage": null,
    "redirectUrl": "https://portal.example.com/onboarding/done",
    "createdAt": "2026-10-07T09:15:02.000Z",
    "completedAt": null,
    "expiresAt": "2026-10-21T09:15:02.000Z",
    "cancelledAt": "2026-10-08T14:30:00.000Z"
  },
  "meta": {
    "requestId": "req_1f0b6c2e9a7d4f58b3c1e6a9d2f4b7c0"
  }
}