Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with Planoly

To integrate Replit with Planoly, obtain a Planoly API key from your account settings, store it in Replit Secrets (lock icon πŸ”’), and call the Planoly REST API from your Python or Node.js backend to upload media, schedule Instagram and Pinterest posts, and manage your visual content grid. Deploy with Autoscale for event-driven scheduling or Reserved VM for automated content pipelines.

What you'll learn

  • How to obtain a Planoly API key and configure it in Replit Secrets
  • How to upload images and videos to Planoly's media library from Python and Node.js
  • How to schedule Instagram and Pinterest posts with captions and hashtags via the API
  • How to retrieve your Planoly content calendar and scheduled post data programmatically
  • How to automate visual content pipelines from asset creation to scheduled social publishing
Book a free consultation
4.9Clutch rating ⭐
600+Happy partners
17+Countries served
190+Team members
Intermediate13 min read25 minutesMarketingMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with Planoly, obtain a Planoly API key from your account settings, store it in Replit Secrets (lock icon πŸ”’), and call the Planoly REST API from your Python or Node.js backend to upload media, schedule Instagram and Pinterest posts, and manage your visual content grid. Deploy with Autoscale for event-driven scheduling or Reserved VM for automated content pipelines.

Why Connect Replit to Planoly?

Planoly is purpose-built for visual content planning β€” it is the platform of choice for Instagram-first brands that care deeply about feed aesthetics and grid cohesion. Its API enables developers to inject media and captions directly into Planoly's scheduling queue from external systems, removing the manual step of uploading images through the web interface.

The most compelling use case is connecting Planoly to your creative production workflow. When a design tool, e-commerce platform, or brand asset management system produces new content, your Replit backend can automatically upload those assets to Planoly, attach optimized captions with hashtag groups, and slot the posts into the content calendar at predetermined times. This is particularly valuable for brands managing high-volume Instagram feeds with dozens of posts per month.

Planoly is stronger than Later in grid preview β€” it lets users see exactly how their Instagram feed will look before publishing β€” and has native Pinterest support as a first-class feature. Its API exposes these core scheduling capabilities, making it a powerful tool to automate from Replit. Store your Planoly API credentials in Replit Secrets (lock icon πŸ”’ in the sidebar) and always call the API from server-side code, since credentials grant access to your connected social profiles.

Integration method

Standard API Integration

You connect Replit to Planoly by obtaining API credentials from your Planoly account, storing them in Replit Secrets, and making authenticated HTTP requests to the Planoly REST API from your server-side Python or Node.js code. The API supports uploading images and videos, scheduling posts with captions and hashtags, managing content drafts, and retrieving your posting calendar. All requests use API key authentication via request headers.

Prerequisites

  • A Replit account with a Python or Node.js project created
  • A Planoly account with at least one social profile connected (paid plan recommended for API access)
  • A Planoly API key (available from Planoly support or your enterprise account settings)
  • Basic familiarity with REST APIs and multipart file uploads
  • Node.js 18+ or Python 3.10+ (both available on Replit by default)

Step-by-step guide

1

Get Your Planoly API Key and Profile ID

Planoly's API access is available for business accounts and through their developer program. To obtain API credentials, log in to your Planoly account and navigate to Settings (accessible via your profile avatar). Look for an API or Integrations section. If you do not see an API section in your settings, contact Planoly support at support@planoly.com to request API access for your account. Mention that you are building an automation integration and need API credentials. Planoly's API is available to business plan subscribers and approved developer partners. Once API access is enabled, you will receive an API key (sometimes called an access token). This key authenticates all your API requests. You will also need your Planoly profile ID β€” the unique identifier for the Instagram or Pinterest profile you want to post to. Profile IDs can be retrieved from the API once authenticated, or may be provided in your account dashboard. Copy your API key and note your profile ID. In the next step you will add both to Replit Secrets.

Pro tip: Planoly may provide separate API keys for Instagram profiles and Pinterest profiles. If you manage multiple platforms, note which key corresponds to which platform so you can target posts correctly.

Expected result: You have a Planoly API key and at least one profile ID ready to add to Replit Secrets.

2

Store Planoly Credentials in Replit Secrets

Open your Replit project and click the lock icon πŸ”’ in the left sidebar to open the Secrets pane. Add the following secrets: - Key: PLANOLY_API_KEY β€” Value: your Planoly API key - Key: PLANOLY_PROFILE_ID β€” Value: your Planoly Instagram profile ID If you post to Pinterest as well, add: - Key: PLANOLY_PINTEREST_PROFILE_ID β€” Value: your Planoly Pinterest profile ID Click 'Add Secret' after each entry. Replit encrypts these values and injects them as environment variables at runtime. They never appear in your file tree, source code, or Git history. Access them in Python with os.environ['PLANOLY_API_KEY']; in Node.js, use process.env.PLANOLY_API_KEY. Restart your Repl after adding secrets to ensure they are available to the running process. Never hardcode Planoly credentials in your source files. Replit's Secret Scanner will flag hardcoded tokens, and exposed credentials would allow anyone to post to your connected social media profiles.

Pro tip: If your Planoly API key rotates or is revoked, update the PLANOLY_API_KEY secret in Replit and restart the Repl. All API calls will immediately start using the new key without code changes.

Expected result: PLANOLY_API_KEY and PLANOLY_PROFILE_ID appear in the Replit Secrets pane and are accessible as environment variables.

3

Upload Media to Planoly with Python

The Planoly API workflow starts with uploading media to your Planoly media library before scheduling posts. Media can be uploaded from a URL or as a binary file. The upload endpoint returns a media ID that you reference when creating a scheduled post. Planoly supports JPEG and PNG images for Instagram posts, and MP4 video for Instagram video posts. Image dimensions should match Instagram's recommended specs: square (1080x1080), portrait (1080x1350), or landscape (1080x566) to maintain grid quality. Install requests with pip install requests in the Replit shell. The module below shows uploading from URL and from file, plus retrieving your profile information.

planoly_client.py
1import os
2import requests
3from typing import Optional
4
5API_KEY = os.environ["PLANOLY_API_KEY"]
6PROFILE_ID = os.environ["PLANOLY_PROFILE_ID"]
7BASE_URL = "https://api.planoly.com/v1"
8
9HEADERS = {
10 "Authorization": f"Bearer {API_KEY}",
11 "Accept": "application/json"
12}
13
14def get_profile_info() -> dict:
15 """Retrieve profile information to verify credentials."""
16 response = requests.get(
17 f"{BASE_URL}/profiles/{PROFILE_ID}",
18 headers=HEADERS
19 )
20 response.raise_for_status()
21 return response.json()
22
23def upload_media_from_url(image_url: str) -> dict:
24 """
25 Upload an image to Planoly media library from a public URL.
26 Returns media object including the media ID.
27 """
28 response = requests.post(
29 f"{BASE_URL}/profiles/{PROFILE_ID}/media",
30 json={"url": image_url},
31 headers={**HEADERS, "Content-Type": "application/json"}
32 )
33 response.raise_for_status()
34 return response.json()
35
36def upload_media_from_file(file_path: str) -> dict:
37 """
38 Upload an image from a local file to Planoly media library.
39 """
40 with open(file_path, 'rb') as f:
41 filename = os.path.basename(file_path)
42 files = {'file': (filename, f, 'image/jpeg')}
43 headers_no_ct = {k: v for k, v in HEADERS.items()}
44 response = requests.post(
45 f"{BASE_URL}/profiles/{PROFILE_ID}/media",
46 files=files,
47 headers=headers_no_ct
48 )
49 response.raise_for_status()
50 return response.json()
51
52def get_media_library(limit: int = 20) -> list:
53 """List media items in the Planoly media library."""
54 response = requests.get(
55 f"{BASE_URL}/profiles/{PROFILE_ID}/media",
56 params={"limit": limit},
57 headers=HEADERS
58 )
59 response.raise_for_status()
60 return response.json().get('data', [])
61
62def schedule_post(
63 media_id: str,
64 caption: str,
65 scheduled_time: str,
66 first_comment: str = ""
67) -> dict:
68 """
69 Schedule a post to Instagram via Planoly.
70 scheduled_time: ISO 8601 UTC string, e.g. '2026-04-15T14:00:00Z'
71 first_comment: optional hashtag comment posted immediately after publish
72 """
73 payload = {
74 "media_id": media_id,
75 "caption": caption,
76 "scheduled_time": scheduled_time
77 }
78 if first_comment:
79 payload["first_comment"] = first_comment
80
81 response = requests.post(
82 f"{BASE_URL}/profiles/{PROFILE_ID}/posts",
83 json=payload,
84 headers={**HEADERS, "Content-Type": "application/json"}
85 )
86 response.raise_for_status()
87 return response.json()
88
89def get_scheduled_posts(start_date: str, end_date: str) -> list:
90 """
91 Retrieve scheduled posts for a date range.
92 Dates in YYYY-MM-DD format.
93 """
94 response = requests.get(
95 f"{BASE_URL}/profiles/{PROFILE_ID}/posts",
96 params={"start_date": start_date, "end_date": end_date, "status": "scheduled"},
97 headers=HEADERS
98 )
99 response.raise_for_status()
100 return response.json().get('data', [])
101
102# Example usage
103if __name__ == "__main__":
104 # Verify credentials
105 profile = get_profile_info()
106 print(f"Connected profile: {profile.get('username')} ({profile.get('platform')})")
107
108 # Upload image
109 media = upload_media_from_url("https://example.com/product-image.jpg")
110 media_id = media.get('id')
111 print(f"Media uploaded: {media_id}")
112
113 # Schedule post
114 post = schedule_post(
115 media_id=media_id,
116 caption="Introducing our newest collection. Link in bio to shop. ✨",
117 scheduled_time="2026-04-20T14:00:00Z",
118 first_comment="#fashion #newcollection #style #ootd #instafashion"
119 )
120 print(f"Post scheduled: {post.get('id')}")

Pro tip: Use the first_comment parameter for hashtags instead of putting them in the caption. This keeps captions clean and readable while still getting the SEO benefit of hashtags. Instagram users see the caption without the hashtag clutter, while the first comment keeps them discoverable.

Expected result: Running the Python script verifies your Planoly credentials, uploads a test image, and schedules an Instagram post, printing the post ID.

4

Build a Scheduling API with Node.js and Express

An Express server provides HTTP endpoints for triggering Planoly post scheduling from external systems. This is the standard pattern for integrating Planoly into a broader content workflow β€” other systems (CMSs, design tools, e-commerce platforms) POST content to your Replit backend, which handles the Planoly API calls. The server below exposes a POST /schedule endpoint for creating scheduled posts and a GET /calendar endpoint for retrieving the upcoming post calendar. Install dependencies with npm install express axios. For deployment, use Replit Autoscale if this server receives inbound webhooks or user-triggered requests. Autoscale is cost-effective as it scales to zero when idle. Configure your .replit file with the run command set to node server.js.

server.js
1const express = require('express');
2const axios = require('axios');
3
4const app = express();
5app.use(express.json());
6
7const API_KEY = process.env.PLANOLY_API_KEY;
8const PROFILE_ID = process.env.PLANOLY_PROFILE_ID;
9const BASE_URL = 'https://api.planoly.com/v1';
10
11const ploHeaders = {
12 'Authorization': `Bearer ${API_KEY}`,
13 'Content-Type': 'application/json',
14 'Accept': 'application/json'
15};
16
17async function uploadMediaFromUrl(imageUrl) {
18 const res = await axios.post(
19 `${BASE_URL}/profiles/${PROFILE_ID}/media`,
20 { url: imageUrl },
21 { headers: ploHeaders }
22 );
23 return res.data;
24}
25
26async function schedulePost(mediaId, caption, scheduledTime, firstComment = '') {
27 const payload = { media_id: mediaId, caption, scheduled_time: scheduledTime };
28 if (firstComment) payload.first_comment = firstComment;
29 const res = await axios.post(
30 `${BASE_URL}/profiles/${PROFILE_ID}/posts`,
31 payload,
32 { headers: ploHeaders }
33 );
34 return res.data;
35}
36
37// POST /schedule β€” upload media and schedule a post
38app.post('/schedule', async (req, res) => {
39 const { imageUrl, caption, scheduledTime, hashtags, profileId } = req.body;
40
41 if (!imageUrl || !caption || !scheduledTime) {
42 return res.status(400).json({
43 error: 'imageUrl, caption, and scheduledTime are required'
44 });
45 }
46
47 const targetProfile = profileId || PROFILE_ID;
48
49 try {
50 // Upload media
51 const mediaData = await uploadMediaFromUrl(imageUrl);
52 const mediaId = mediaData?.id;
53
54 if (!mediaId) {
55 return res.status(500).json({ error: 'Media upload failed' });
56 }
57
58 // Schedule the post
59 const post = await schedulePost(
60 mediaId,
61 caption,
62 scheduledTime,
63 hashtags || ''
64 );
65
66 res.json({
67 success: true,
68 mediaId,
69 postId: post?.id,
70 scheduledTime
71 });
72 } catch (error) {
73 console.error('Planoly API error:', error.response?.data || error.message);
74 res.status(500).json({ error: 'Failed to schedule post' });
75 }
76});
77
78// GET /calendar β€” get scheduled posts for current week
79app.get('/calendar', async (req, res) => {
80 const today = new Date();
81 const endDate = new Date(today);
82 endDate.setDate(today.getDate() + 7);
83 const startStr = today.toISOString().split('T')[0];
84 const endStr = endDate.toISOString().split('T')[0];
85
86 try {
87 const response = await axios.get(
88 `${BASE_URL}/profiles/${PROFILE_ID}/posts`,
89 {
90 headers: ploHeaders,
91 params: { start_date: startStr, end_date: endStr, status: 'scheduled' }
92 }
93 );
94 res.json(response.data);
95 } catch (error) {
96 console.error('Planoly API error:', error.response?.data || error.message);
97 res.status(500).json({ error: 'Failed to retrieve calendar' });
98 }
99});
100
101app.listen(3000, '0.0.0.0', () => {
102 console.log('Planoly integration server running on port 3000');
103});

Pro tip: Add a validation step before calling the Planoly API to confirm the image URL is publicly accessible and the scheduled_time is in the future. Planoly will return errors for inaccessible images and past schedule times, but catching these server-side provides clearer error messages to your users.

Expected result: POST /schedule uploads media to Planoly and schedules an Instagram post, returning the post ID and scheduled time.

Common use cases

E-Commerce Product Feed Automation

When a new product is added to your Shopify or WooCommerce store, a Replit backend fetches the product image and description, uploads the image to Planoly, and schedules a grid-optimized Instagram post with the product name, price, and relevant hashtags already formatted.

Replit Prompt

Build a Flask webhook endpoint that receives new product creation events from a store, downloads the product image, uploads it to Planoly via the API, and schedules an Instagram post with a caption template including the product name and price, using PLANOLY_API_KEY from Replit Secrets.

Copy this prompt to try it in Replit

Content Calendar Batch Scheduling

A Replit script reads a weekly content plan from a Google Sheet or database, processes the image assets and captions, uploads everything to Planoly in batch, and schedules each post at the optimal time for each day of the week β€” turning a spreadsheet content plan into a fully scheduled Planoly calendar.

Replit Prompt

Create a Python script that reads a content schedule from a CSV file containing image URLs, captions, and publish dates, then uploads each image to Planoly and schedules the corresponding Instagram post at the specified time using the Planoly REST API.

Copy this prompt to try it in Replit

UGC Curation and Republishing

A Replit backend monitors a UGC approval queue, and when a piece of user-generated content is approved, automatically downloads the approved image, uploads it to Planoly with a repost caption crediting the original creator, and adds it to the next available slot in the Instagram content calendar.

Replit Prompt

Write a Node.js Express endpoint that receives approved UGC from an internal approval tool, downloads the image, uploads it to Planoly, and schedules an Instagram post with a caption crediting the original creator, using the PLANOLY_PROFILE_ID to target the correct social profile.

Copy this prompt to try it in Replit

Troubleshooting

API returns 401 Unauthorized on all requests

Cause: The API key is missing from the Authorization header, has been revoked, or is incorrectly formatted. Planoly expects a Bearer token.

Solution: Verify PLANOLY_API_KEY is set in Replit Secrets and that the Authorization header is 'Bearer YOUR_KEY'. If the key was recently regenerated, update the secret in Replit and restart the Repl.

typescript
1HEADERS = {
2 "Authorization": f"Bearer {os.environ['PLANOLY_API_KEY']}",
3 "Accept": "application/json"
4}

Media upload returns 422 or 400 with image format error

Cause: The image URL is not publicly accessible, the file format is unsupported, or the image dimensions do not meet Instagram's aspect ratio requirements.

Solution: Ensure the image URL is publicly accessible (test by opening it in a private browser tab). Use JPEG or PNG formats. For Instagram feed posts, use aspect ratios between 4:5 (portrait) and 1.91:1 (landscape). Square images (1:1) are safest for grid consistency.

typescript
1# Recommended Instagram dimensions
2# Square: 1080 x 1080 (1:1)
3# Portrait: 1080 x 1350 (4:5) β€” maximum height
4# Landscape: 1080 x 566 (1.91:1) β€” minimum height

Scheduled post fails with 'profile not found' or 404 error

Cause: The PLANOLY_PROFILE_ID is incorrect, the profile has been disconnected from Planoly, or the API key does not have access to the specified profile.

Solution: Retrieve your profile ID by calling GET /v1/profiles with just the API key header (no profile ID in the URL). List all accessible profiles and their IDs. Update PLANOLY_PROFILE_ID in Replit Secrets with the correct ID.

typescript
1def get_all_profiles() -> list:
2 """List all profiles accessible with this API key."""
3 response = requests.get(
4 f"{BASE_URL}/profiles",
5 headers=HEADERS
6 )
7 response.raise_for_status()
8 return response.json().get('data', [])
9
10# Run this to find your profile ID
11profiles = get_all_profiles()
12for p in profiles:
13 print(f"ID: {p['id']} | Platform: {p['platform']} | Username: {p['username']}")

Post shows as 'draft' in Planoly instead of 'scheduled'

Cause: The scheduled_time was not provided or was in an incorrect format, causing Planoly to save the post as a draft rather than scheduling it.

Solution: Ensure scheduled_time is included in the POST body and is a valid future UTC datetime in ISO 8601 format (e.g., '2026-04-20T14:00:00Z'). Double-check that the time is in the future and in UTC, not local time.

typescript
1from datetime import datetime, timezone, timedelta
2
3# Schedule 2 days from now at 2pm UTC
4publish_time = datetime.now(timezone.utc).replace(hour=14, minute=0, second=0)
5if publish_time < datetime.now(timezone.utc):
6 publish_time += timedelta(days=1)
7publish_time += timedelta(days=1) # push to next day for safety
8scheduled_time = publish_time.strftime("%Y-%m-%dT%H:%M:%SZ")

Best practices

  • Always store PLANOLY_API_KEY and PLANOLY_PROFILE_ID in Replit Secrets β€” never hardcode credentials in source files
  • Use first_comment for hashtags rather than including them in the caption to keep captions visually clean while maintaining discoverability
  • Upload media before scheduling and verify the media ID is present in the upload response before proceeding to the scheduling step
  • Validate that all scheduled_time values are in UTC and in the future before submitting to the API
  • Use Instagram-recommended aspect ratios (square 1:1 or portrait 4:5) to prevent grid visual inconsistencies
  • Retrieve existing scheduled posts before batch scheduling to avoid posting duplicate content to your feed
  • Store Planoly post IDs in your application database to enable future updates, deletions, or status tracking
  • Deploy on Replit Autoscale for HTTP-triggered workflows and use Reserved VM for scheduled content pipeline scripts that run on a daily or weekly cadence

Alternatives

Frequently asked questions

How do I connect Replit to Planoly?

Obtain a Planoly API key from your account settings or by contacting Planoly support, then add it as PLANOLY_API_KEY in Replit Secrets (lock icon πŸ”’ in the sidebar). Use Bearer token authentication in the Authorization header when calling the Planoly REST API from your Python or Node.js backend.

Does Planoly require a paid plan for API access?

Planoly API access is available for business plan subscribers and through Planoly's developer partner program. If you do not see API settings in your account, contact Planoly support to request access. The free plan does not include API integration capabilities.

How do I upload images to Planoly from Replit?

POST to /v1/profiles/{profileId}/media with either a public image URL in the JSON body or a multipart file upload. The response includes a media ID. Use this media ID when calling the scheduling endpoint to attach the image to your post.

Can I schedule Instagram Reels or carousel posts via the Planoly API?

API support for Reels and carousel (multi-image) posts depends on Planoly's current API capabilities. Check the Planoly API documentation for the latest supported post types. For standard single-image feed posts, the scheduling endpoint works as described in this guide.

What is the best way to use hashtags with Planoly's API?

Use the first_comment parameter when scheduling posts to post hashtags as the first comment rather than including them in the caption. This keeps captions clean and readable for viewers while retaining the discoverability benefits of hashtags in the first comment.

What deployment type should I use on Replit for Planoly integrations?

Use Autoscale deployment for HTTP-triggered scheduling endpoints that receive webhooks from other tools. Use Reserved VM if you run a scheduled content pipeline β€” for example, a script that reads a weekly content plan from a database and schedules all posts for the coming week.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation β€” no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.