---
agentTools:
  projectIndex: https://developers.pipefy.com/llms.txt
---

# Custom App Data

Store your app's own data, and attach links to cards

Your app can store its own data inside Pipefy, so it does not need a database of its own for small amounts of state — an API token, a user preference, an ID mapping to an external system.

It can also attach links to cards, which Pipefy renders in the card's attachment list and hands back to your app later.

Apps can only read and write **their own** data. One app cannot see another app's keys, and cannot detach another app's attachments.

# Storing data

## p.set()

```javascript
p.set(scope, visibility, key, value);
```

Stores a value against a `card`, `pipe` or `organization`. Returns a `Promise`.

> ⚠️ Don't depend on what `p.set()` resolves to
>
> The write itself is reliable, but the resolved value is not: on some surfaces `p.set()` resolves to the stored result and on others it resolves to `undefined`. Use it as a completion signal — `p.set(...).then(function () { ... })` — and read the value back with [`p.get()`](#pget) if you need to confirm it.

### Scope

Scope decides *what the data is attached to*, and therefore who can reach it.

| Scope          | Description                                                         |
| :------------- | :------------------------------------------------------------------ |
| `organization` | Available to every pipe across the organization                     |
| `pipe`         | Attached to the current pipe. Other pipes cannot read it.           |
| `card`         | Attached to the current card. Other cards and pipes cannot read it. |

### Visibility

Visibility decides *which users* can reach it, within that scope.

| Visibility | Description                                                                               |
| :--------- | :---------------------------------------------------------------------------------------- |
| `private`  | Only the current user. Use this for anything personal — API tokens, per-user credentials. |
| `public`   | Every user who can reach that scope                                                       |

> ⚠️ Never store secrets as `public`
>
> `public` means every user with access to the card, pipe or organization can read the value through your app. Access tokens, refresh tokens, API keys and personal data belong in `private`, always. Note also that `public` and `private` describe visibility *inside* Pipefy — neither is a substitute for encrypting data you consider sensitive.

### Examples

```javascript
// A personal token — only visible to me, only on this pipe
p.set('pipe', 'private', 'token', 'VERY_IMPORTANT_TOKEN');

// A card annotation everyone on the card can see
p.set('card', 'public', 'emoji', '😈');

// A setting shared by every pipe in the organization
p.set('organization', 'public', 'default_region', 'us-east-1');
```

`value` is stored as a string. To keep structured data, serialise it yourself:

```javascript
p.set('pipe', 'public', 'settings', JSON.stringify({ region: 'us-east-1', retries: 3 }));
```

Keep stored values small — this is a place for configuration and identifiers, not a general-purpose datastore. If you are storing more than a few kilobytes per key, or need to query across records, use your own backend and store only the reference here.

## p.get()

```javascript
p.get(scope, visibility, key);
```

Reads back a value your app stored. The `scope`, `visibility` and `key` must match what you passed to `p.set()` — `p.get('pipe', 'public', 'token')` will not find something written as `private`.

Resolves to the stored value, or a falsy value if the key was never set.

```javascript
p.get('pipe', 'private', 'token')
  .then(function (token) {
    if (!token) {
      // First run — nothing stored yet
      return showConnectPrompt();
    }
    console.log(token);
  })
  .catch(function (error) {
    console.error(error);
    p.showNotification('Could not load your settings', 'error');
  });
```

Reading JSON back:

```javascript
p.get('pipe', 'public', 'settings').then(function (raw) {
  var settings = raw ? JSON.parse(raw) : { region: 'us-east-1', retries: 3 };
  apply(settings);
});
```

# Card attachments

Attachments are links your app puts on a card. Pipefy shows them in the card's attachment list, and your app can read them back to render its own view of them — which is how the `card-tab` and `card-badges` features usually decide what to display.

## p.attach()

```javascript
p.attach({ url, name });
```

Attaches a link to the current card. Returns a `Promise`.

```javascript
p.attach({
  url: 'https://github.com/piedpiper/hotdog-app/pull/1000',
  name: 'Hotdog App PR #1000',
}).then(function (result) {
  console.log(result);
  p.showNotification('Pull request attached', 'success');
}).catch(function (error) {
  console.error(error);
  p.showNotification('Could not attach the pull request', 'error');
});
```

## p.detach()

```javascript
p.detach(id);
```

Removes an attachment from the current card. Resolves to `true` on success. Apps can only detach attachments they attached themselves.

```javascript
p.detach('231jasd').then(function (result) {
  console.log(result); // true
});
```

The `id` comes from [`p.cardAttachments()`](https://developers.pipefy.com/docs/get-pipefy-data#pcardattachments).

> 📘 `p.dettach()`
>
> A misspelled alias, `p.dettach()`, exists for backward compatibility. Use `p.detach()`.

## The attachment round trip

The three functions form one workflow:

```javascript
// 1. Attach something
p.attach({ url: prUrl, name: 'PR #' + prNumber })
  // 2. Read back everything this app has attached
  .then(function () { return p.cardAttachments(); })
  .then(function (attachments) {
    console.log(attachments);
    // [{ id: "LPpssdkK", url: "https://github.com/...", name: "PR #1000" }]

    // 3. Remove one by id
    return p.detach(attachments[0].id);
  });
```

[`p.cardAttachments()`](https://developers.pipefy.com/docs/get-pipefy-data#pcardattachments) is documented on the Get Pipefy data page.

# See also

* [Get Pipefy data](https://developers.pipefy.com/docs/get-pipefy-data) — read the current card, pipe and fields
* [card-badges](https://developers.pipefy.com/docs/card-badges) and [card-tab](https://developers.pipefy.com/docs/card-tab) — features that render attachments
* [Make API calls](https://developers.pipefy.com/docs/make-api-calls) — for data that belongs in Pipefy proper, not in app storage