# Postman collection

> Fork the Adeli Postman collection, set your API key, and publish a first post without writing code.

Canonical: <https://www.tryadeli.com/docs/postman>

Adeli publishes a Postman collection with every `/api/v1` request, a guided
folder that publishes your first post, and an environment that holds your API
key. It is the quickest way to try the API without writing code.

The collection lives in the public
[Adeli API workspace](https://www.postman.com/try-adeli/adeli-api) on Postman.
It is generated from the same [OpenAPI document](https://www.tryadeli.com/docs/openapi.json) the API
is described by, so every request body is a valid example rather than a
schema placeholder.

## Fork the collection

[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/58072869-ed9713ee-2806-494c-98ab-9e30ade77186?action=collection%2Ffork\&source=rip_markdown\&collection-url=entityId%3D58072869-ed9713ee-2806-494c-98ab-9e30ade77186%26entityType%3Dcollection%26workspaceId%3De93bccf3-1ae6-4ad3-bf6c-3b495a1b35b7)

1. Select **Run in Postman** above and fork the collection into a personal or
   team workspace you control. Or open the
   [Adeli API workspace](https://www.postman.com/try-adeli/adeli-api) and
   select **Fork** on the **Adeli API** collection.
2. In the workspace, fork the **Adeli** environment too.
3. In your workspace, select the **Adeli** environment in the top-right
   environment picker.

Forking, rather than importing a copy, lets you pull updates when the API
changes. See [Staying current](https://www.tryadeli.com/docs/postman#staying-current).

## Set your API key

Create a key in the dashboard under
[Settings → API keys](https://app.tryadeli.com/settings/api-keys). It starts
with `rk_live_`. Paste it into the environment's `apiKey` value.

Every request inherits `Authorization: Bearer {{apiKey}}` from the
collection, so there is nothing to set per request. The environment's
`baseUrl` is `https://app.tryadeli.com`; change it to
`http://localhost:3000` if you run Adeli locally.

> **Warning: Keep the key out of public workspaces**
>
> `apiKey` is a secret variable, so Postman masks it on screen. Put the key in
> its **current value**, which stays on your machine, and leave the initial
> value empty, because initial values are shared with anyone who can see the
> workspace. Never paste the key into the collection or a request. If one
> leaks, delete it under Settings → API keys; revocation is immediate.

## Start here: publish your first post

The first folder, **Start here: publish your first post**, publishes one image
to an Instagram account connected to your organization. Run its requests in
order: each one saves the ids the next one needs into collection variables.

Before you start, set two collection variables to describe the image you will
upload: `uploadContentType` (`image/jpeg`, `image/png`, or `image/webp`) and
`uploadFileSize`, the file's exact size in bytes. S3 checks the size, so it
must match the file.

| Request                               | What it does                                                                                                                                | Saves                                    |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| 1. Check your API key                 | `GET /api/v1/me` confirms the key works and names your default profile.                                                                     | `profileId`                              |
| 2. Find a connected Instagram account | `GET /api/v1/accounts?platform=instagram` lists the accounts you can publish from.                                                          | `accountId`, `profileId`                 |
| 3. Prepare the upload                 | `POST /api/v1/media/uploads` returns a short-lived S3 upload URL and the headers it needs.                                                  | `uploadId`, `uploadUrl`, `uploadHeaders` |
| 4. Upload the file to S3              | `PUT {{uploadUrl}}` sends your image straight to S3. Choose the file under **Body → binary**.                                               | —                                        |
| 5. Publish the post                   | `POST /api/v1/posts` publishes the staged image with a caption.                                                                             | `jobId`                                  |
| 6. Check the post's status            | `GET /api/v1/posts/instagram/status` reports `queued`, `processing`, `published`, or `failed`. Send it again until the post is `published`. | `postId`                                 |

> **Warning: Step 5 posts for real**
>
> There is no sandbox mode. The post goes live on the account step 2 found, so
> use an account you do not mind posting to, and delete the post on Instagram
> afterwards if it was only a test.

No account connected yet? Connect one in the dashboard, or send **Profiles →
Start connecting a social account** and open the `authUrl` it returns. See
[the connect reference](https://www.tryadeli.com/docs/api/connect).

## Variables

Requests in the other folders use the same collection variables, so an id one
request saves is ready for the next. Ids nothing saves for you are left blank
for you to fill.

| Variable                                              | Set by                                                          |
| ----------------------------------------------------- | --------------------------------------------------------------- |
| `profileId`                                           | 1. Check your API key, or 2. Find a connected Instagram account |
| `accountId`                                           | 2. Find a connected Instagram account                           |
| `secondAccountId`                                     | You, for a publication to two accounts                          |
| `uploadId`, `uploadUrl`, `uploadHeaders`              | Prepare direct media uploads                                    |
| `uploadContentType`, `uploadFileSize`                 | You, before preparing an upload                                 |
| `thumbnailUploadId`                                   | You, for a YouTube thumbnail                                    |
| `jobId`                                               | Publish a post, for an Instagram post                           |
| `postId`                                              | Check an Instagram post's publishing status                     |
| `connectionSessionId`                                 | Start connecting a social account                               |
| `publicationId`                                       | Publish one post to several accounts                            |
| `webhookId`                                           | Create a webhook                                                |
| `commentId`, `adAccountId`, `campaignId`, `adGroupId` | You, from a list request                                        |

Optional query parameters start switched off. Tick one in the **Params** tab
to send it.

## Uploading media

Every request that publishes media takes a staged `upload_id`, never the file
itself. Prepare the upload, `PUT` the file to the returned `url` with the
returned headers sent unchanged, then publish with `upload_id`. The
**Prepare direct media uploads** request saves the `uploadId` that the
**Publish a post** requests use. See
[media uploads](https://www.tryadeli.com/docs/api/posts/create-media-uploads) for the limits per
platform.

**Publish a post** has one request per network, named after it: Instagram
image or Reel, Facebook photo, TikTok video, YouTube video, X, Bluesky, and
LinkedIn image or document. The **TikTok video (multipart, legacy)** request
uploads the file in the request itself and stays only for compatibility.

## Staying current

The collection is regenerated from `/docs/openapi.json` and republished
whenever the API changes. In your fork, open the collection's **…** menu and
select **Pull changes** to bring in new and changed requests. Local edits to a
request you also change in the fork can conflict; Postman shows both versions
and lets you choose.

## Troubleshooting

| Response                  | Cause                                                                                                                         |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `401 unauthorized`        | `apiKey` is empty, or the **Adeli** environment is not selected.                                                              |
| `403 permission_required` | The connected account has not granted a permission this request needs. The error names it; reconnect the account to grant it. |
| `402 usage_limit_reached` | The workspace used its free monthly allowance. See [Billing](https://www.tryadeli.com/docs/billing).                          |
| `403` from S3 in step 4   | A header from step 3 was changed or left out, or the upload URL expired. Send step 3 again.                                   |
| `422 invalid_media`       | The file does not match `uploadContentType` or `uploadFileSize`, or exceeds the platform's limit.                             |

Every error has the same JSON envelope. See [Errors](https://www.tryadeli.com/docs/errors).
