POST/api/v4/social/bulk-posts

Create posts in bulk

Validates and queues up to 500 social posts in one request, returning a job to poll for per-row results.

Requires an API key. See Authentication for header format and key rotation.

Parameters

Body

A nested field marked required applies only when you send its parent. If the parent is optional and you omit it, its required children do not apply.

NameTypeRequiredDescription
inputobjectrequiredWrapper object. The entire request body must be nested under `input`.
input.postsarray of objectsrequiredThe rows to create, 1 to 500 of them. Each row is the same object POST /social/posts takes as its `input`; the per-row fields are listed below.
input.namestringoptionalOptional label for the job itself, to identify it in your own logs. Not shown to any audience.
input.posts[].socialProfileIdstringrequiredUUID of the brand publishing this row. Rows may target different brands in one request.
input.posts[].namestringrequiredInternal name for the post.
input.posts[].platformsarray of stringsrequiredPlatforms for this row: `FACEBOOK`, `INSTAGRAM`, `TWITTER` (X), `LINKEDIN`, `PINTEREST`. Each must already have a connection on that row's brand.
input.posts[].contentstringrequiredThe post body.
input.posts[].actionstringrequired`DRAFT`, `SCHEDULE` (requires a schedule) or `PUBLISH`.
input.posts[].mediaUrlsarray of stringsoptionalPublic https image URLs. Required when the row targets Instagram or Pinterest.
input.posts[].videoUrlsarray of stringsoptionalPublic https video URLs.
input.posts[].linkstringoptionalLink to attach where the platform supports one.
input.posts[].scheduledAtstringoptionalISO-8601 publish instant with an offset. Alternative to `scheduleDate` + `scheduleTime`, never both.
input.posts[].scheduleDatestringoptional`YYYY-MM-DD`, interpreted in that row's brand timezone. Send with `scheduleTime`.
input.posts[].scheduleTimestringoptional`HH:MM`, interpreted in that row's brand timezone. Send with `scheduleDate`.
input.posts[].connectedChannelIdsarray of stringsoptionalRestrict this row to specific connections by ID.
input.posts[].clientReferencestringoptionalYour own identifier for this row, echoed back on the matching job result. The most reliable way to reconcile a batch against your own records.

Sample request

Ready-to-paste body. Replace placeholder IDs and values with yours.

Request body
{  "input": {    "name": "Autumn campaign load",    "posts": [      {        "socialProfileId": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902",        "name": "Autumn week 1",        "platforms": ["INSTAGRAM", "FACEBOOK"],        "content": "Week one of the autumn collection: the Fairfield oak sideboard, finished by hand in the workshop.",        "mediaUrls": ["https://cdn.example.com/social/autumn-w1.jpg"],        "action": "SCHEDULE",        "scheduleDate": "2026-10-02",        "scheduleTime": "09:30",        "clientReference": "campaign-4471-slot-01"      },      {        "socialProfileId": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902",        "name": "Autumn week 2",        "platforms": ["INSTAGRAM", "FACEBOOK", "LINKEDIN"],        "content": "Week two: the Halcyon armchair. Sixty hours of work, one chair.",        "mediaUrls": ["https://cdn.example.com/social/autumn-w2.jpg"],        "action": "SCHEDULE",        "scheduleDate": "2026-10-09",        "scheduleTime": "09:30",        "clientReference": "campaign-4471-slot-02"      },      {        "socialProfileId": "a90f7c22-5db1-4e83-9f40-2b7c6a1e5d33",        "name": "Eastside autumn teaser",        "platforms": ["INSTAGRAM"],        "content": "Something solid is arriving next week. Stay tuned.",        "mediaUrls": ["https://cdn.example.com/social/eastside-teaser.jpg"],        "action": "SCHEDULE",        "scheduledAt": "2026-10-01T08:00:00-04:00",        "clientReference": "campaign-4471-slot-03"      }    ]  }}

Responses

200The whole batch validated. A job was queued, poll GET /social/bulk-posts/{bulkJobId} for per-row results.
Response
{  "data": {    "createBulkSocialMediaPosts": {      "success": true,      "error": [],      "job": {        "id": "9b3f18d0-7a26-4c51-8e94-1f0d5c6b7a82",        "status": "QUEUED",        "totalCount": 3,        "processedCount": 0,        "successCount": 0,        "failureCount": 0,        "createdAt": "2026-09-28T14:04:52Z",        "updatedAt": "2026-09-28T14:04:52Z",        "results": []      }    }  }}
200At least one row failed validation, so **nothing was created**. `success` is `false`, no job is returned, and each rejected row is reported with its 0-based `index`.
Response
{  "data": {    "createBulkSocialMediaPosts": {      "success": false,      "error": [        {          "message": "SY95050: Bulk validation failed, no posts were created",          "code": "SY95050",          "contextInfo": null        }      ],      "job": {        "id": null,        "status": "FAILED",        "totalCount": 3,        "processedCount": 0,        "successCount": 0,        "failureCount": 2,        "createdAt": "2026-09-28T14:04:52Z",        "updatedAt": "2026-09-28T14:04:52Z",        "results": [          {            "index": 1,            "clientReference": "campaign-4471-slot-02",            "socialProfileId": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902",            "platforms": ["INSTAGRAM", "FACEBOOK", "LINKEDIN"],            "status": "INVALID",            "socialPostId": null,            "postStatus": null,            "errors": [              {                "message": "SY95045: No connected channel for LINKEDIN on this brand",                "code": "SY95045",                "contextInfo": [{ "key": "platform", "value": "LINKEDIN" }]              }            ]          },          {            "index": 2,            "clientReference": "campaign-4471-slot-03",            "socialProfileId": "a90f7c22-5db1-4e83-9f40-2b7c6a1e5d33",            "platforms": ["INSTAGRAM"],            "status": "INVALID",            "socialPostId": null,            "postStatus": null,            "errors": [              {                "message": "SY95046: scheduledAt must carry a UTC offset",                "code": "SY95046",                "contextInfo": null              }            ]          }        ]      }    }  }}
401Unauthenticated, missing or invalid API key.

Creates many social posts in one request. The rows travel in the request payload — there is no file upload and no CSV, just an array of the same objects POST /social/posts takes one at a time. Up to 500 rows per request.

Use case: loading a quarter of content in one call. Your planning tool has the client's whole content calendar. Build one row per slot, tag each with your own clientReference, and send them together. The batch either succeeds as a unit or tells you precisely which rows to fix. Store the returned job.id and poll GET /social/bulk-posts/{bulkJobId} until status is terminal, then reconcile each result by its clientReference.

The whole batch is validated up front

Validation runs across every row before anything is created, and the batch is atomic at that stage:

  • If any row is invalid, nothing is created. success is false, SY95050 comes back in error, and each bad row appears in job.results[] with its 0-based index, its clientReference, and the reason in errors[]. Fix those rows and resend the whole batch.
  • If every row is valid, a job is queued, success is true, and you get a job.id. Individual rows can still fail later, when the platform rejects them at publish time; that shows up on the job, not here.

Reconcile by clientReference where you can and by index otherwise — the rows themselves are not echoed back, so those two fields are the only link to your own data.

Notes.

  • The request body must be wrapped in an input object, with the rows in input.posts.
  • Check success, not the HTTP status. A batch-wide rejection is an HTTP 200 with success: false and SY95050 in error.
  • Maximum 500 rows per request. A larger array is rejected outright with SY95048 and nothing is created; split it and send several batches.
  • The brand on each row is socialProfileId. brandId is only ever a URL path token, and this route has no path token at all.
  • Rows may target different brands. Each row's platforms are checked against that row's own brand, so a platform connected on one brand and not another fails only the rows that need it.
  • Each row follows the same schedule rules as a single post: scheduledAt or scheduleDate + scheduleTime, never both, and scheduleDate / scheduleTime are read in that row's brand timezone. Mixing the two forms across different rows in one batch is fine.
  • Rate limits apply to the request, not to the rows: a 500-row batch costs one request against your budget. See Rate limits.

Write operation: not executed against the live account. The request and response shown are built from the API schema; this publishes to real social accounts when run.

Request
curl -X POST 'https://listingsapi.com/api/v4/social/bulk-posts' \  -H "Authorization: API $LISTINGSAPI_KEY" \  -H 'Content-Type: application/json' \  -d '{    "input": {      "name": "Autumn campaign load",      "posts": [        {          "socialProfileId": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902",          "name": "Autumn week 1",          "platforms": [            "INSTAGRAM",            "FACEBOOK"          ],          "content": "Week one of the autumn collection: the Fairfield oak sideboard, finished by hand in the workshop.",          "mediaUrls": [            "https://cdn.example.com/social/autumn-w1.jpg"          ],          "action": "SCHEDULE",          "scheduleDate": "2026-10-02",          "scheduleTime": "09:30",          "clientReference": "campaign-4471-slot-01"        },        {          "socialProfileId": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902",          "name": "Autumn week 2",          "platforms": [            "INSTAGRAM",            "FACEBOOK",            "LINKEDIN"          ],          "content": "Week two: the Halcyon armchair. Sixty hours of work, one chair.",          "mediaUrls": [            "https://cdn.example.com/social/autumn-w2.jpg"          ],          "action": "SCHEDULE",          "scheduleDate": "2026-10-09",          "scheduleTime": "09:30",          "clientReference": "campaign-4471-slot-02"        },        {          "socialProfileId": "a90f7c22-5db1-4e83-9f40-2b7c6a1e5d33",          "name": "Eastside autumn teaser",          "platforms": [            "INSTAGRAM"          ],          "content": "Something solid is arriving next week. Stay tuned.",          "mediaUrls": [            "https://cdn.example.com/social/eastside-teaser.jpg"          ],          "action": "SCHEDULE",          "scheduledAt": "2026-10-01T08:00:00-04:00",          "clientReference": "campaign-4471-slot-03"        }      ]    }  }'