# PATCH /v1/projects/:projectId/sdk-apps/:appId (/docs/api/reference/sdk-apps/patch-sdk-app)



<Endpoint method="PATCH" path="/v1/projects/:projectId/sdk-apps/:appId" auth="Bearer" scope="projects:write" phase="1" />

Patch any user-editable field on an SDK app, enable or disable CAPI forwarding per ad platform, or force a key rotation. Omitted fields stay unchanged.

Passing `rotateKey: true` is the only case where the response includes a plaintext `apiKey` — the old key is invalidated immediately. Clients using the old key start receiving `401` on the ingest endpoint within seconds.

Enabling CAPI requires two things already stored on the project layer: the `pixel_id` for the ad platform and a vault-encrypted access token. Set these up via the ad-accounts OAuth flow before flipping `capi.{platform}.enabled` here.

<Parameters
  title="Path"
  rows="[
  { name: 'projectId', type: 'string', required: true, description: 'Project ID.' },
  { name: 'appId', type: 'string', required: true, description: 'SDK app ID.' },
]"
/>

<Parameters
  title="Body"
  rows="[
  { name: 'name', type: 'string', description: '1–128 chars.' },
  { name: 'bundleId', type: 'string', description: 'iOS builds only.' },
  { name: 'androidPackage', type: 'string', description: 'Android builds only.' },
  { name: 'webDomain', type: 'string', description: 'Web builds only.' },
  { name: 'capi', type: 'object', description: 'Per-platform CAPI toggles. Shape: { meta?: { enabled }, tiktok?: { enabled }, apple?: { enabled } }.' },
  { name: 'rotateKey', type: 'boolean', description: 'If true, create a fresh API key and invalidate the current one. The new key is returned once.' },
]"
/>

## Example request [#example-request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl -X PATCH "https://api.layers.com/v1/projects/9cb958b5-11b5-4e30-8675-5d075d52da7c/sdk-apps/app_8ffb9410eb0eb848264f8a65" \
      -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..." \
      -H "Content-Type: application/json" \
      -d '{
        "capi": { "meta": { "enabled": true } },
        "rotateKey": true
      }'
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    const app = await layers.sdkApps.update(
      "9cb958b5-11b5-4e30-8675-5d075d52da7c",
      "app_8ffb9410eb0eb848264f8a65",
      {
        capi: { meta: { enabled: true } },
        rotateKey: true,
      }
    );
    // Store app.apiKey — the previous key is dead.
    ```
  </Tab>

  <Tab value="Python">
    ```python
    app = layers.sdk_apps.update(
        project_id="9cb958b5-11b5-4e30-8675-5d075d52da7c",
        app_id="app_8ffb9410eb0eb848264f8a65",
        capi={"meta": {"enabled": True}},
        rotate_key=True,
    )
    # Store app["apiKey"] — the previous key is dead.
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="200" description="OK">
  ```json
  {
    "appId": "app_8ffb9410eb0eb848264f8a65",
    "name": "Acme Coffee iOS",
    "platform": "ios",
    "bundleId": "com.acmecoffee.ios",
    "androidPackage": null,
    "webDomain": null,
    "ingestEndpoint": "https://in.layers.com/l/events",
    "capi": {
      "meta": { "enabled": true }
    },
    "createdAt": "2026-04-18T19:25:22Z",
    "lastRotatedAt": "2026-04-18T19:31:42Z",
    "lastEventAt": "2026-04-18T19:42:11Z",
    "apiKey": "sk_app_3mNp...x9F"
  }
  ```

  The response body is the full SDK-app shape (same as `GET /v1/projects/:projectId/sdk-apps/:appId`) plus `apiKey` when `rotateKey: true` was set. `capi` only carries entries for platforms you've toggled — pixel/lastForwardAt fill in once the ad-account OAuth flow has stored credentials and the relay has forwarded an event.
</Response>

## Errors [#errors]

| Status | Code              | When                                                                                                               |
| ------ | ----------------- | ------------------------------------------------------------------------------------------------------------------ |
| 422    | `VALIDATION`      | Unknown field, platform-identifier mismatch (e.g. passing `androidPackage` on an iOS app).                         |
| 401    | `UNAUTHENTICATED` | Missing or invalid key.                                                                                            |
| 403    | `FORBIDDEN_SCOPE` | Key lacks `projects:write`.                                                                                        |
| 404    | `NOT_FOUND`       | Project or SDK app does not exist.                                                                                 |
| 409    | `CONFLICT`        | CAPI enable requested for a platform without a `pixel_id` or vault token configured. Connect the ad account first. |
| 429    | `RATE_LIMITED`    | Write budget exhausted.                                                                                            |

## See also [#see-also]

* [`GET /v1/projects/:projectId/sdk-apps/:appId`](/docs/api/reference/sdk-apps/get-sdk-app) — read current state
* [Ad accounts OAuth](/docs/api/reference/social-accounts/oauth-url) — prerequisite for CAPI enable
