Skip to content
SocialMint
FeaturesDemoPricingFAQLog inStart free

SocialMint REST API v1

Help center · n8n setup guide

n8n community node: n8n-nodes-socialmint (coming to npm)

Automate brand publishing with the Agency plan, including Agency trials. Manage keys and webhooks · Download OpenAPI 3.1

Authentication and scopes

Create a named API key and copy it immediately. The key is shown once and stored as a SHA-256 hash. Send it over HTTPS in the Authorization header. Revocation is immediate. API access returns 403 if Agency access ends.

curl https://socialmint.app.mintapis.com/api/v1/me \
  -H "Authorization: Bearer $SOCIALMINT_API_KEY"

Scopes: posts:read for lists and details, posts:write for creation, retry and deletion, brands:read for brands and channels, webhooks:manage for endpoint registration, listing, deletion, tests and delivery logs. Existing keys retain their scopes; create a new key with webhooks:manage when needed. A posts:read-only key never receives an approval URL. Workspaces allow at most 20 active keys; revoke one before creating another. GET /me accepts any valid key and returns workspace, plan, limits and scopes.

Endpoints

All paths below are relative to https://socialmint.app.mintapis.com/api/v1. IDs belong to your workspace; foreign resource IDs return 404. Responses use snake_case fields.

MethodPathBehavior
GET/meGet workspace, plan and limits
GET/brandsList workspace brands
GET/brands/{id}/channelsList brand channels
GET/postsList posts in ascending UUID order
POST/postsCreate a draft or schedule a post
GET/posts/{id}Get post, targets and event history
DELETE/posts/{id}Delete an unstarted draft or scheduled post
PATCH/posts/{id}Reschedule an unstarted scheduled or approved post
POST/posts/{id}/retryRetry eligible failed targets; inspect needs_review remotely first
GET/webhooksList webhook endpoints without secrets
POST/webhooksRegister a webhook endpoint
DELETE/webhooks/{id}Delete endpoint and cancel open deliveries
POST/webhooks/{id}/testQueue a signed ping event
GET/webhooks/{id}/deliveriesList latest deliveries
POST/mediaUpload an image
POST/posts/bulkPlan up to 200 posts with individual results

Plan several posts

POST /posts/bulk accepts an array of 1–200 CreatePost objects, with at most one image per post and a total request limit of 2 MiB. It requires posts:write. Dates use ISO 8601 with an explicit offset; omit scheduled_at for drafts. The bulk editor and CSV import at /app/posts/bulk are available on every plan; API access keeps the existing Agency requirement.

[
  {
    "brand_id": "11111111-1111-4111-8111-111111111111",
    "body": "Hello from SocialMint",
    "media_urls": [],
    "channel_ids": [
      "22222222-2222-4222-8222-222222222222"
    ],
    "scheduled_at": "2030-01-07T09:00:00+01:00",
    "requires_approval": false
  }
]

HTTP 200 returns data, an ordered array of results with zero-based index, status (201 for success), id and post_status, or error.code and error.message. Invalid rows do not prevent other rows from saving. More than 200 rows returns 422. Reuse an Idempotency-Key to replay the exact response for 24 hours without duplicate posts; changed input returns 409. Retry failed rows in a new request with a new key.

CSV header: date,time,text,channels,image_url,requires_approval. Use UTF-8 (BOM accepted), comma or semicolon delimiters, quoted multiline text, YYYY-MM-DD dates and HH:MM times in the selected brand’s timezone. Separate channel display names or providers with |; a provider selects all matching channels. Approval accepts true/false, yes/no or 1/0. Review the preview and row errors before saving. Auto-distribute spreads posts evenly across a start date, day count and time slots.

Create a post

curl https://socialmint.app.mintapis.com/api/v1/posts \
  -H "Authorization: Bearer $SOCIALMINT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: campaign-42-post-1" \
  --data '{
  "brand_id": "11111111-1111-4111-8111-111111111111",
  "body": "Hello from SocialMint",
  "media_urls": [],
  "channel_ids": [
    "22222222-2222-4222-8222-222222222222"
  ],
  "scheduled_at": "now",
  "requires_approval": true
}'

Omit scheduled_at to save a draft. Otherwise use "now" or a future ISO 8601 date with an explicit timezone, such as 2027-01-20T09:00:00+01:00. Scheduled posts require at least one active channel. Set requires_approval to true to hold publication until the customer approves. A scheduled approval request returns approval_url. GET /posts/{id} also returns approvals[] and, when requires_approval is true and the key also has posts:write, approval_url (null for drafts without a link).

The same composer rules apply: nonempty body up to 100,000 characters, provider text limits including appended links, up to four public HTTPS media URLs, HTTP(S) link_url (up to 2048 characters, without invisible controls) and channels belonging to the selected editable brand. Inactive owned channels and unresolvable/private media hosts return 422 with a field reference for media_urls. Unknown channels or channels outside the selected brand return 404. Approval links require Agency; existing requests remain readable after downgrade. Invalid input returns 422; ordinary JSON bodies are limited to 64 KiB (bulk: 2 MiB), with a 10-second read deadline.

{
  "id": "33333333-3333-4333-8333-333333333333",
  "brand_id": "11111111-1111-4111-8111-111111111111",
  "body": "Hello from SocialMint",
  "media_urls": [],
  "link_url": null,
  "scheduled_at": "2026-09-09T12:00:00Z",
  "requires_approval": true,
  "status": "pending_approval",
  "approval_url": "https://socialmint.app.mintapis.com/r/<token>",
  "created_at": "2026-09-09T12:00:00Z",
  "updated_at": "2026-09-09T12:00:00Z"
}

Read brands, channels and workspace

GET /brands → {"data":[{"id":"<brand_id>","name":"Acme","slug":"acme","timezone":"Europe/Berlin","color":"#047857"}]}
GET /brands/<brand_id>/channels → {"data":[{"id":"<channel_id>","provider":"mastodon","display_name":"Acme","status":"active","url":"https://example.social/@acme"}]}
GET /me → {"workspace":{"id":"<workspace_id>","name":"Agency","slug":"agency"},"plan":"agency","limits":{"brands":15,"seats":5,"requests_per_minute":60},"scopes":["posts:read"]}

List, inspect, retry and delete

GET /posts?brand_id=&status=&limit=20&cursor= accepts a limit of 1–100 (default 20). Omit unused filters. Results are ordered by ascending UUID; pass next_cursor into the next request until it is null. New concurrent inserts may require a later full sync.

GET /posts → {"data":[{"id":"<post_id>","brand_id":"<brand_id>","body":"Hello","status":"scheduled", "media_urls":[],"link_url":null,"scheduled_at":"2027-01-20T08:00:00Z","requires_approval":false,"created_at":"2026-09-09T12:00:00Z","updated_at":"2026-09-09T12:00:00Z"}],"next_cursor":null}
GET /posts/<post_id> → { ...post, "targets":[{"id":"<target_id>","channel_id":"<channel_id>","status":"failed","remote_url":null,"last_error_human":"Reconnect this channel.","attempts":1,"warnings":[]}],"events":[{"id":"<event_id>","target_id":"<target_id>","type":"failed","message":"Attempt 1 failed","created_at":"2026-09-09T12:01:00Z"}]}
POST /posts/<post_id>/retry → 200, same shape as GET /posts/<post_id>
DELETE /posts/<post_id> → 204, empty body

Retry resets eligible failed, held or needs_review targets to queued. Check the remote channel before retrying needs_review to avoid duplicates. Posts must already be scheduled and approved; reconnect inactive channels first. Delete permits only draft/scheduled posts whose publishing attempts have not started; otherwise it returns 409.

Upload images

POST /media requires posts:write. Send multipart file (optional brand_id), or JSON with Base64 data and optional brand_id. The 201 response contains id, url, width, height and bytes. Use url in a post’s media_urls. URLs are public to anyone who has the link. JPEG, PNG, WebP and GIF are supported, up to 5 MiB per image and four images per post. Agency storage is 2 GiB per workspace. Oversized files return 413; invalid images or exhausted storage return 422. Uploads are limited to 30/minute per user/workspace in addition to the API key budget. Provider-specific image limits still apply; images are not resized.

Errors, rate limits and idempotency

{"error":{"code":"validation_error","message":"Use up to four HTTPS media URLs."}}

401: missing/invalid/revoked key; 403: Agency or scope required; 404: unknown route or resource (including foreign/unknown channel IDs); 405: unsupported method (Allow header); 409: invalid status or idempotency conflict; 413: oversized body; 422: invalid input; 429: rate limit; 500: temporary server failure.

Each key permits 60 requests per minute across all endpoints and server processes. A 429 response includes Retry-After in seconds. POST /posts accepts Idempotency-Key (1–200 printable non-space ASCII characters). For 24 hours, repeated equivalent validated input with that key and API key returns the same 201 body, even after the post changes. Different input returns 409. Concurrent duplicates are serialized. Validation failures do not reserve the key. Use a new key for a new post.

Webhooks

Create a public HTTPS endpoint in API settings and save its one-time signing secret. Select post.published (all active targets published), post.failed (terminal failure or partial failure), post.needs_review (manual verification needed) and approval.decided (customer decision). Test requests emit ping with data.test=true, independently of subscriptions.

Register and manage through the API

Use a key with webhooks:manage. POST /webhooks accepts url and events and returns 201 with id, url, events, active and the one-time secret. Save it immediately. GET /webhooks returns data[] without secrets. A workspace supports ten endpoints, including disabled ones; an eleventh returns 422. Only public HTTPS URLs are accepted.

curl https://socialmint.app.mintapis.com/api/v1/webhooks \
  -H "Authorization: Bearer $SOCIALMINT_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"url":"https://example.com/socialmint","events":["post.published","approval.decided"]}'

GET /webhooks → {"data":[{"id":"<endpoint_id>","url":"https://example.com/socialmint","events":["post.published","approval.decided"],"active":true}]}
POST /webhooks/<endpoint_id>/test → 202 {"id":"<delivery_id>","event":"ping","status":"pending"}
GET /webhooks/<endpoint_id>/deliveries?limit=20 → {"data":[{"id":"<delivery_id>","event":"ping","status":"delivered","attempts":1,"response_status":204,"pause_reason":null,"next_attempt_at":null,"created_at":"2026-09-09T12:00:00Z"}]}
DELETE /webhooks/<endpoint_id> → 204, empty body

Deliveries are newest first, default 20, limit 1–100. Logs remain readable after deletion. Delete cancels pending and paused deliveries and destroys the secret. Test requires an active endpoint and queues a signed ping for the next worker tick.

Event catalog and example payloads

post.published: all active targets published. post.failed: terminal failure or partial failure. post.needs_review: a target needs manual verification. approval.decided: approved or changes_requested. ping: explicit endpoint test, not a subscription option.

[
  {
    "id": "44444444-4444-4444-8444-444444444444",
    "event": "post.published",
    "created_at": "2026-09-09T12:00:00Z",
    "data": {
      "post_id": "33333333-3333-4333-8333-333333333333",
      "status": "published"
    }
  },
  {
    "id": "44444444-4444-4444-8444-444444444444",
    "event": "post.failed",
    "created_at": "2026-09-09T12:00:00Z",
    "data": {
      "post_id": "33333333-3333-4333-8333-333333333333",
      "status": "partially_failed"
    }
  },
  {
    "id": "44444444-4444-4444-8444-444444444444",
    "event": "post.needs_review",
    "created_at": "2026-09-09T12:00:00Z",
    "data": {
      "post_id": "33333333-3333-4333-8333-333333333333",
      "target_id": "22222222-2222-4222-8222-222222222222"
    }
  },
  {
    "id": "44444444-4444-4444-8444-444444444444",
    "event": "approval.decided",
    "created_at": "2026-09-09T12:00:00Z",
    "data": {
      "post_id": "33333333-3333-4333-8333-333333333333",
      "brand_id": "11111111-1111-4111-8111-111111111111",
      "decision": "approved",
      "decided_at": "2026-09-09T12:00:00Z",
      "has_comment": false,
      "post_url": "https://socialmint.app.mintapis.com/app/posts/33333333-3333-4333-8333-333333333333"
    }
  },
  {
    "id": "44444444-4444-4444-8444-444444444444",
    "event": "ping",
    "created_at": "2026-09-09T12:00:00Z",
    "data": {
      "test": true
    }
  }
]
{
  "id": "<event_id>",
  "event": "approval.decided",
  "created_at": "2026-09-09T12:00:00Z",
  "data": {
    "post_id": "<post_id>",
    "brand_id": "<brand_id>",
    "decision": "approved",
    "decided_at": "2026-09-09T12:00:00Z",
    "has_comment": false,
    "post_url": "https://socialmint.app.mintapis.com/app/posts/<post_id>"
  }
}

Delivery runs asynchronously on the 30-second worker tick with at most five attempts. Failures retry after 1, 5, 30 and 30 minutes. Only 2xx acknowledges delivery. Redirects and private/reserved addresses are rejected. Deliveries are at least once; deduplicate payload.id. X-SocialMint-Delivery identifies the endpoint delivery. Disabling an endpoint stops future claims; an already in-flight request may finish. Delivery requires Agency access.

X-SocialMint-Signature is t=<Unix seconds>,v1=<hex HMAC-SHA256>. Sign the exact timestamp + "." + raw JSON bytes with the signing secret. Reject timestamps older than five minutes and compare in constant time:

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody must be the exact request bytes, before JSON parsing.
export function verify(rawBody, header, secret) {
  const match = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header ?? '');
  if (!match) return false;
  const [, t, v1] = match;
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac('sha256', secret)
    .update(t + '.').update(rawBody).digest();
  return timingSafeEqual(expected, Buffer.from(v1, 'hex'));
}
// After verification: deduplicate payload.id, durably enqueue, return 2xx.

Approval event data contains only post_id, brand_id, decision, decided_at, has_comment and post_url. Reviewer names and comments are available to authorized readers in GET /posts/{id} under approvals[] (decision, reviewer_name, comment, created_at; decided_at remains a compatibility alias). Previously stored outbox names and comments are removed by migration.

Delivery runs separately after publishing, with a 10-second budget, four concurrent requests and a five-second request timeout. Disable pauses pending deliveries; Enable resumes them. Delete cancels open deliveries and removes the endpoint signing secret while retaining the log. Requests already in flight may reach the receiver. Lost Agency access pauses without consuming attempts and resumes automatically after access returns.

Access requires a current trial_end for trials, or current_period_end plus three days for paid plans. Past-due access is additionally limited to seven days from the first payment failure. Missing dates fail closed. Every v1 response uses Cache-Control: no-store; routing errors also use the JSON error contract (HEAD has no body).

n8n

n8n node coming soon; use HTTP Request node meanwhile.

Create a Header Auth credential with name Authorization and value Bearer followed by your API key. In HTTP Request choose POST, URL https://socialmint.app.mintapis.com/api/v1/posts, JSON body mode, and the create-post JSON above. Add Idempotency-Key using a stable source record ID, for example campaign-42-post-1. Use an n8n Webhook node with a production HTTPS URL to receive events; verify the signature over raw bytes before processing.

SocialMint

Social scheduling and client approvals for agencies.

Made in Passau, Germany

FeaturesInteractive demoPricingRoadmapHelp centerAPI docs
ImpressumPrivacy PolicyTerms of ServiceData Processing AgreementContact
CompareHootsuite alternative for agenciesPostiz alternative

© 2026 productivity-boost.com Betriebs UG (haftungsbeschränkt) & Co. KG