Accounts
Account Status
Check whether an account can publish, see when its access expires, and reconnect or disconnect it.
Every account has a status that tells you whether it can publish. Check it before you publish, and reconnect an account as soon as it stops being active.
import { Configuration, AccountsApi } from "@onepostly/sdk";
const accountsApi = new AccountsApi(
new Configuration({ accessToken: process.env.ONEPOSTLY_API_KEY })
);
const response = await accountsApi.getAccount({
id: "acc_YOUR_LINKEDIN_ACCOUNT_ID",
});
console.log(response);{
"id": "acc_YOUR_LINKEDIN_ACCOUNT_ID",
"platform": "linkedin",
"displayName": "Your Brand",
"handle": "Your Brand",
"avatarUrl": "https://cdn.onepostly.com/avatars/yourbrand.jpg",
"status": "active",
"canAutoRenew": false,
"tokenExpiresAt": "2027-04-30T10:00:00.000Z",
"profile": "Default",
"metadata": {},
"createdAt": "2027-03-01T10:00:00.000Z",
"updatedAt": "2027-03-01T10:00:00.000Z"
}Status Values
status | Meaning | What to do |
|---|---|---|
active | The account works | Nothing |
expired | The access ran out and could not renew | Reconnect the account |
revoked | The platform or the owner withdrew the access | Reconnect the account |
error | The account cannot be used until reconnected | Reconnect the account |
New values can be added, so treat anything but active as needing a reconnect. Until then, actions fail.
The API does not return disconnected accounts. You see disconnected only in the account.disconnected webhook.
Token Expiry
Two fields tell you whether an account stays connected on its own.
| Field | Meaning |
|---|---|
canAutoRenew | true when the access renews by itself, so expiry never needs a reconnect |
tokenExpiresAt | When the access expires, or null when it never does |
When canAutoRenew is false, the account works until tokenExpiresAt and then reads expired. It depends on what the platform granted at sign-in, so check it per account. Each platform page lists its access lifetimes under Connect.
Expiring Accounts
An account that cannot renew sends account.expiring about 7 days before tokenExpiresAt, or right after connecting when less time is left. Reconnect it before then to keep publishing.
| Event | When you get it |
|---|---|
account.expiring | About 7 days before the access runs out. Once per authorization |
account.expired | The access ran out, the next time the account is used |
account.revoked | The platform rejected the access, or the owner withdrew it |
account.connected | A connect or reconnect, with reconnected and the new tokenExpiresAt |
account.disconnected | An account was disconnected |
See Account Webhooks for the payloads.
Reconnect an Account
Reconnect when status is not active, when account.expiring arrives, or when a post fails with TOKEN_INVALID. The account keeps its id, profile and posts, and is not billed as new.
POST /v1/accounts/{id}/reconnect needs a read_write key. Check type in the response.
type | Platforms | Response |
|---|---|---|
oauth | All except Bluesky | A sign-in url and its expiresAt |
account | Bluesky | The reconnected account |
Platforms With a Sign-In
Send the redirectUrl the browser returns to. It is required with an API key.
import { Configuration, AccountsApi } from "@onepostly/sdk";
const accountsApi = new AccountsApi(
new Configuration({ accessToken: process.env.ONEPOSTLY_API_KEY })
);
const response = await accountsApi.reconnectAccount({
id: "acc_YOUR_LINKEDIN_ACCOUNT_ID",
reconnectAccountBody: {
"redirectUrl": "https://yourapp.com/oauth/onepostly"
},
});
console.log(response);{
"type": "oauth",
"url": "https://www.linkedin.com/oauth/v2/authorization?response_type=code&state=eyJhbGciOiJIUzI1NiJ9",
"expiresAt": "2027-03-15T10:10:00.000Z"
}Send the user to the url within 10 minutes. They must sign in with the same account, and no Page picker is shown.
A success redirects with the usual parameters plus reconnected=1. Another account returns error=RECONNECT_MISMATCH. Other failures use the Redirect Errors codes.
Bluesky
Send the identifier and a new appPassword. The identifier has to belong to the same Bluesky account. The response has type set to account, with the reconnected account in account.
import { Configuration, AccountsApi } from "@onepostly/sdk";
const accountsApi = new AccountsApi(
new Configuration({ accessToken: process.env.ONEPOSTLY_API_KEY })
);
const response = await accountsApi.reconnectAccount({
id: "acc_YOUR_BLUESKY_ACCOUNT_ID",
reconnectAccountBody: {
"identifier": "yourbrand.bsky.social",
"appPassword": "qrst-uvwx-yzab-cdef"
},
});
console.log(response);{
"type": "account",
"account": {
"id": "acc_YOUR_BLUESKY_ACCOUNT_ID",
"platform": "bluesky",
"displayName": "Your Brand",
"handle": "yourbrand.bsky.social",
"avatarUrl": "https://cdn.onepostly.com/avatars/yourbrand.jpg",
"status": "active",
"canAutoRenew": true,
"tokenExpiresAt": "2027-03-15T12:00:00.000Z",
"profile": "Default",
"metadata": {},
"createdAt": "2027-03-01T10:00:00.000Z",
"updatedAt": "2027-03-15T10:00:00.000Z"
}
}Disconnect an Account
DELETE /v1/accounts/{id} needs a read_write key and returns 204. Only YouTube also withdraws the access on the platform. Elsewhere, the owner can remove Onepostly in the platform's app settings.
import { Configuration, AccountsApi } from "@onepostly/sdk";
const accountsApi = new AccountsApi(
new Configuration({ accessToken: process.env.ONEPOSTLY_API_KEY })
);
const response = await accountsApi.deleteAccount({
id: "acc_YOUR_LINKEDIN_ACCOUNT_ID",
});
console.log(response);| After a disconnect | Result |
|---|---|
| Published posts | Stay on the platform |
| Its posts in Onepostly | Keep their history |
GET /v1/accounts/{id} | 404 ACCOUNT_NOT_FOUND |
| Billing | Stops counting from the next UTC day |
| Webhook | account.disconnected |
An account is also disconnected when its owner removes Onepostly in Facebook, Instagram or Threads settings, or asks the platform to delete their data. Connecting it again counts as a new account.
Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
REDIRECT_URL_REQUIRED | 400 | No redirectUrl with an API key | Send redirectUrl |
INVALID_REDIRECT_URL | 400 | Not a full https URL, or has credentials | Send a full https URL |
BLUESKY_RECONNECT_APP_PASSWORD | 400 | identifier or appPassword is missing | Send both |
RECONNECT_MISMATCH | 400 | Another Bluesky account's identifier | Use the original account |
FORBIDDEN | 403 | A read_only key | Use a read_write key |
ACCOUNT_NOT_FOUND | 404 | No such account, or already disconnected | Use a current id |
AUTH_FAILED | 422 | Bluesky rejected the credentials | Create a new App Password |
PLATFORM_MAINTENANCE | 503 | Connections to the platform are paused | Try again later |
See Errors for every other code.