APIREST · OpenAPI 3.1
One typed REST API for the whole platform.
Everything the Medal apps do is available over HTTPS at https://io.medalsocial.com/api/v1 — posts, emails, contacts and deals, bookings, portal, GDPR, scan, helpdesk, webhooks, channels, capability confirmations and workspaces.
From API key to first response.
bashYour first requestcurl https://io.medalsocial.com/api/v1/posts \ -H "Authorization: Bearer $MEDAL_API_KEY"
Authenticate
Create an API key in your workspace settings and send it as Authorization: Bearer medal_… — keys are scoped to a single workspace, so an integration can never reach the wrong data. OAuth access tokens work too; pair one with an x-workspace-id header so the request resolves to the right workspace.
One base URL, every resource
https://io.medalsocial.com/api/v1 covers posts, emails, contacts, deals, bookings, portal, GDPR, scan, helpdesk, webhooks, channels, capability confirmations and workspaces. Everything speaks JSON in and JSON out.
jsonErrors are JSON{ "error": { "code": "UNAUTHORIZED", "message": "Missing or invalid Authorization header" } }
Rate limits, retries and pagination
Reads are limited to 300 requests per minute (burst 100) and writes to 60 per minute (burst 30). Email send allows 100 per minute, email batch 10 per minute, contact import 5 per minute, and GDPR export 5 per hour. Back off on 429 and honour Retry-After. List endpoints paginate by cursor: pass next_cursor back to fetch the following page.
Verify every webhook
Deliveries carry an X-Medal-Signature header — an HMAC-SHA256 over {timestamp}.{rawBody} — alongside X-Medal-Timestamp. Recompute the signature over the raw body and compare it before you trust a payload.
A validated OpenAPI 3.1 contract
There is no public OpenAPI URL. The validated contract ships inside the npm package instead — @medalsocial/sdk/openapi.json, openapi.yaml and openapi-types — so you generate clients, mock servers or agent tools from a version you pin.