URL: /code/integrations/calls/call · Id: `page:/code/integrations/calls/call`

# Integration.call

> Reach any endpoint of a connected account, with your token filled in.

`POST https://api.sb/{your-domain}/integrations/call`

Reach any endpoint of a connected account, with your token filled in.

- **Action class:** None
- **Approval:** Runs on its own
- **Emits:** `Integration.called`
- **Sites:** [2 sites](#on-each-venue)
- **Price:** Free

```text title="Run it · Ask"
How many followers does my X account have right now?
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Integration.call({ integration: 'int_X8dNa4kR2p', method: 'GET', path: '/2/users/me?user.fields=public_metrics' })
```

```json title="Run it · Response"
{
  "api": "https://api.sb/leaseline.app",
  "status": 200,
  "body": {
    "data": {
      "id": "1849230117745823744",
      "name": "Dana Okafor",
      "username": "danaokafor",
      "public_metrics": {
        "followers_count": 412,
        "following_count": 388,
        "tweet_count": 1093,
        "listed_count": 7
      }
    }
  },
  "integration": "https://api.sb/leaseline.app/integrations/int_X8dNa4kR2p",
  "action": {
    "operation": "Integration.call",
    "mode": "try",
    "status": "done"
  }
}
```

Sends one request to any endpoint of a connected account, with your token filled in on the server. [The hub’s definition of `Integration.call`](https://startupbuilder.dev/business/nouns/integration/call).</HubDefinition>

## Inputs
| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `integration` | `Integration` | Required | The Integration to call through. |
| `method` | `string` | Required | The HTTP method; `GET` runs at once. |
| `path` | `string` | Required | The upstream path, inside the Integration’s grants. |
| `body` | `json` | `null` | The request body. Unset for a `GET`, which sends none. |

## Outputs
| Field | Type | What `null` means |
| --- | --- | --- |
| `status` | `integer` | Never null once the request leaves the platform: the answering API’s own HTTP status, passed through unchanged. |
| `body` | `json` | The answer carried no body, as on a `204`. |
| `integration` | `Integration` | Never null. |

## Effects
**Action class**

None: no approval rule names it, so it runs within its seat’s Permissions and Limits

**Modes**

- `try`: Sends a `GET` as is, since it changes nothing; any other method runs the account’s own validate-only path where one exists, and changes nothing.
- `send`: Returns a pending Action: a `GET` settles at once, any other method after its delay window.
- `do`: Waits for the answer and returns its status and body unchanged.

**Idempotency**

Only with a key: the same `Idempotency-Key` and input return the first Action, and the same key with other input returns `409`. The key never leaves the platform: a `POST` retried after a timeout replays the first Action instead of posting twice.

**Saved or shared**

The Action keeps the method, the path and the status that came back. The token never appears in the Action, a log or the response.

**Emits**

`Integration.called` with `{ integration, method, path, status }`

**Performed by**

[Integration Engineer](https://startupbuilder.dev/agents/engineering/integration-engineer)

**Price**

Free on your own account: the platform charges nothing for the call.

## On each Venue
| Site | Fields | Formats |
| --- | --- | --- |
| [Google Analytics](#google-analytics) | None. | None. |
| [Google Business Profile](#google-business-profile) | None. | None. |

### Google Analytics
Through [Google Analytics](/code/integrations/google-analytics).

### Google Business Profile
Through [Google Business Profile](/code/integrations/google-business-profile).

## What try does
| Account | What try does |
| --- | --- |
| [Google Analytics](/code/integrations/google-analytics#try) | Reads run for real, because a report changes nothing; `try` stores no rows, builds no audience and marks no event. |
| [Google Business Profile](/code/integrations/google-business-profile#try) | Returns the update or the answer as it will show on your profile; nothing posts. |

## Refuses when
This call has no refusals of its own. Every call through an account can also meet [the shared account refusals](/code/refusals#accounts): [`grant-missing`](/code/refusals#grant-missing), [`needs-reauth`](/code/refusals#needs-reauth), [`account-not-connected`](/code/refusals#account-not-connected), [`over-mandate`](/code/refusals#over-mandate), [`quota-reached`](/code/refusals#quota-reached), [`venue-rejected`](/code/refusals#venue-rejected).

## When it waits
| Fact | Value |
| --- | --- |
| `send` returns | For any method but `GET`, a pending Action, `reason: 'awaitingTime'`, while its delay window runs; a `GET` returns `done` at once. |
| Delivered by | `Integration.called` |

## Example

**Ask**

```text
How many followers does my X account have right now?
```

**API**

```bash
curl -X POST "https://api.sb/leaseline.app/integrations/call?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"integration":"int_X8dNa4kR2p","method":"GET","path":"/2/users/me?user.fields=public_metrics"}'
```

The response is the one in the Run it window above.

**CLI**

```bash
npx startup-builder do Integration.call --try --data '{"integration":"int_X8dNa4kR2p","method":"GET","path":"/2/users/me?user.fields=public_metrics"}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Integration.call({ integration: 'int_X8dNa4kR2p', method: 'GET', path: '/2/users/me?user.fields=public_metrics' })"
  }
}
```

**SDK**

```ts
import { $ } from 'startup-builder'

const result = await $.try.Integration.call({
  integration: 'int_X8dNa4kR2p',
  method: 'GET',
  path: '/2/users/me?user.fields=public_metrics',
})
```

To retry, send the same `Idempotency-Key`: the retry returns the first answer for $0. A new key reads again.

A `sk_test_` key answers these the same way every time, at $0 ([every test value](/code/data#test-values)).

| Test value | Always returns | What it is for |
| --- | --- | --- |
| `int_test_needs_reauth` | Refuses with [`needs-reauth`](/code/refusals#needs-reauth) | Every call through it answers as if the account had ended the sign-in, so your reconnect path runs. |
| `int_test_x` | Refuses with [`grant-missing`](/code/refusals#grant-missing) | It holds only the post-and-reply grant, so a call to change follows refuses before it leaves the platform. |
| `maxCost: 0.0001` | Refuses with [`max-cost`](/code/refusals#max-cost) | Any priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap. |
| `rate-limited.test` | Refuses with [`rate-limited`](/code/refusals#rate-limited) | Any call naming this hostname answers 429 with Retry-After, so your retry logic runs. |
| `sources-busy.test` | Refuses with [`sources-busy`](/code/refusals#sources-busy) | Any call naming this hostname answers 503 as if every route were busy, and nothing is spent. |

## Used by
- **Workflows:** [Index the site](/capabilities/get-indexed/index-the-site) · [Search readout](/capabilities/measure/search-readout)
- **Agent tasks:** [Message test](/capabilities/run-ads/message-test)
- **Integrations:** [Google Analytics](/code/integrations/google-analytics) · [Google Business Profile](/code/integrations/google-business-profile)

## Related
[`Integration.connect`](/code/integrations/calls/connect) · [`Handle.connect`](/code/integrations/calls/connect-handle) · [`Mandate.authorize`](/code/integrations/calls/authorize)