Build a platform
Build a platform
Everything else in these docs assumes the accounts you post to are your own. If you are posting on behalf of your customers, profiles are how you keep them apart.
#The model
A profile is one of your end customers. You create one per customer, connect their accounts into it, and post with profileId. A post that names a profile can only reach that profile's connections, and a post that names none can only reach the accounts outside every profile, which are your own. Billing does not change, because yeetpost bills accounts rather than people: every connection counts on the same per-account ladder, you get one invoice, and you re-bill your customers however you like. An account can hold 1000 profiles at once, and a deleted one does not count toward that.
externalId is your own id for the same customer, so their row in your database and their profile here agree without a second lookup table. It is optional, and unique across your live profiles: a second profile with the same one is refused with 409 profile_external_id_conflict.#1. Create a profile
One call per customer, at the moment you sign them up. Keep the id that comes back next to their row in your database.
curl -X POST "https://api.yeetpost.com/api/v2/profiles" \
-H "x-api-key: $YEETPOST_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "Acme Coffee",
"externalId": "cus_4821"
}'{
"profile": {
"id": "b2d1f0a3-5c6e-4f70-8a9b-0c1d2e3f4a5b",
"name": "Acme Coffee",
"externalId": "cus_4821",
"createdAt": "2026-08-29T09:24:11.412Z"
}
}GET /profiles lists yours newest first, paged with limit (1–100, default 25) and offset. PATCH /profiles/{profileId} takes a name, an externalId, or both.
#2. Connect their accounts into it
Connecting an account into a profile is a dashboard job today: pick the customer in Connect for on the connections screen and connect as usual. The hosted connect URL, which puts the same flow behind a link of your own so your customer never sees our dashboard, is the next piece of this and is not shipped yet.
The same account connected into two profiles is two connections, with their own slugs, history and queue, and it counts twice on your bill, because you are billing two of your own customers for it. Connecting it again inside the same profile is a reconnect and updates that connection in place.
curl "https://api.yeetpost.com/api/v2/connections?profileId=b2d1f0a3-5c6e-4f70-8a9b-0c1d2e3f4a5b" \
-H "x-api-key: $YEETPOST_API_KEY"Leave the filter off and you get every connection of yours, each one saying which profile it belongs to. A profileId that is not one of yours is 400 invalid_request rather than an empty list.
#3. Post with a profileId
Name the profile on the post and the request cannot leave it. A slug belonging to another profile, or to you, fails that one item with invalid_connection while the rest of the request goes out.
curl -X POST "https://api.yeetpost.com/api/v2/posts" \
-H "x-api-key: $YEETPOST_API_KEY" \
-H "content-type: application/json" \
-d '{
"text": "our new roast is out",
"connectionSlugs": ["acme_linkedin"],
"profileId": "b2d1f0a3-5c6e-4f70-8a9b-0c1d2e3f4a5b"
}'Every connection and every post carries a profileId of its own, null when it is one of your own accounts, and profileId is part of the idempotency hash, so the same text to the same slug is a different request inside a profile from outside one. Read a customer's history back the same way:
curl "https://api.yeetpost.com/api/v2/posts?profileId=b2d1f0a3-5c6e-4f70-8a9b-0c1d2e3f4a5b" \
-H "x-api-key: $YEETPOST_API_KEY"POST /post/{connectionSlug} has nowhere to name a profile, so it reaches your own accounts and nothing else. Use POST /posts for a customer's.#4. Listen for the events
Register one webhook for your whole account. connection.created and connection.removed tell you when a customer connects or disconnects an account, and post.sent, post.failed and post.deleted tell you what happened to their posts. Every one of them carries the profileId, so you can route the event to the right customer without a lookup.
curl -X POST "https://api.yeetpost.com/api/v2/webhooks" \
-H "x-api-key: $YEETPOST_API_KEY" \
-H "content-type: application/json" \
-d '{
"url": "https://example.com/hooks/yeetpost",
"events": ["connection.created", "connection.removed", "post.sent", "post.failed"]
}'{
"eventId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"event": "connection.created",
"timestamp": "2026-08-29T09:24:12.004Z",
"connection": {
"id": "3f2a1b4c-5d6e-4f70-8a9b-0c1d2e3f4a5b",
"profileId": "b2d1f0a3-5c6e-4f70-8a9b-0c1d2e3f4a5b",
"platformId": "linkedin",
"slug": "acme_linkedin"
}
}The two ids together are the mapping to persist: the profile is your customer, the connection is what you post to. Reconnecting an account that is already there replaces its credentials rather than making a new connection, so it fires nothing, and deleting a profile fires one connection.removed per account inside it. Signature verification, retries and the delivery log are on the webhooks page.
#A profile is a routing rail, not a boundary
This is the part to read twice. A profile decides which connections a call reaches, and that is all it decides. An account key still reaches any object of the account by id, so GET /posts/{postId} answers for one customer's post whatever profile the caller had in mind.
profileId they belong to. Never ship an account key to a browser or a mobile app you hand to a customer. API keys scoped to one profile are the next piece of this and are not shipped yet.Profiles are not scoped by key type either. A test key manages the same profiles a live key does, and a sandbox connection can sit in a profile, which is how you test a customer's flow without publishing anything. The rest of the security checklist applies unchanged.
#Offboarding a customer
DELETE /profiles/{profileId} disconnects every account in the profile: the credentials are deleted, anything still waiting to be sent is cancelled, the drafts written in it are deleted, and your bill drops to the connections you have left. The answer says how many connections went with it.
curl -X DELETE "https://api.yeetpost.com/api/v2/profiles/b2d1f0a3-5c6e-4f70-8a9b-0c1d2e3f4a5b" \
-H "x-api-key: $YEETPOST_API_KEY"The profile itself is kept out of sight rather than erased. GET, PATCH and DELETE on it answer 404 not_found from then on and it drops out of GET /profiles, but its posts keep their profileId, so GET /posts?profileId=... still lists the history of a customer you have offboarded. Deleting a profile frees its external id, so a customer you take back later is the same externalId on a new profile.
#Compared with Zernio
Zernio's profiles are the same shape as ours, and they are further along: they have hosted connect URLs, headless connect and profile-scoped keys today, and we have the profiles and nothing else yet. One thing we do differently is offboarding: a deleted profile keeps its posts readable here, so a customer you drop does not take their history with them. The whole table is on yeetpost vs Zernio.