v0.9.6 will continue to be supported as-is until further notice except that user streams and app streams are no longer supported for v0.9.6. Streams will only work on v1 going forward.
All items below affect v1.0.0, and most do not affect v0.9.6. If it also affects v0.9.6, it will be marked with v0.9.6+.
recent_deleted_message
Previously, channel.recent_message_id
referenced the last message in a channel.
Now, recent_message_id
will always reference the last non-deleted message in the channel. If there are no messages or only deleted messages in a channel, this field will not be set.
An additional field has been added to channels, called recent_deleted_message_id
. This will only be included if the last message in a channel is a deleted message.
When handling stream markers for channels, you will generally not need to mind deleted messages more recent than the recent_message_id
in a channel. If you make no change to your app, you will simply never have a recent_message
or recent_message_id
that is deleted.
created_at
Channels now include a created_at
field like other objects. Because the date wasn't collected before now, previously created channels will have created_at
retroactively set to the date when the first message was created in the channel. Channels without messages will have it set to "now".
GET /channels/search
can now be searched by created_before
and created_after
.
has_sticky_messages
Channels now include has_sticky_messages
boolean, indicating if there are sticky messages in the channel.
App and User streams now include the field meta.channel_name
when messages are sent from channels of io.pnut.core.chat
type.
Chat room description
is now handled similarly to Post, Message, and User content
objects. Instead of a plain text string, io.pnut.core.chat-settings
-type raw items now have a parsed string for the room description; a whole content
-like object will be embedded, with entities and rendered HTML alongside.
When reposting a post, the repost can be marked as NSFW even when the original was not. Simply including JSON with is_nsfw: true
when reposting will do.
- by Attached File or Poll
Posts, messages, polls, and channels can be searched by what files or polls are attached to them. This way, for example, when you are looking at a file, you can look up if there are any posts that reference the file in their raw
data.
file_id
and poll_id
have been added as filters on various searches.
Additionally, file_kinds
has been added as a search filter for messages and posts, to only return ones with an oEmbed-attached file of the specified kinds.
- by Created At
All search endpoints can now search by created_before
and created_after
.
The polls
app stream type is now functional. The stream sends updates on creation, deletion, every user's first response to a poll, and when the poll closes. Because poll results can only be seen after the poll ends, updates only include the poll object without current results unless it is closed.
Now RSS feeds include OEmbed pictures and audio files in the RSS stream. The feed item descriptions will include HTML, which means in particular they will now include HTML links.
User and App streams no longer work on v0
of the API. They are only available on v1
.
All of the other 1.0 breaking changes on the streamed objects will have to be handled for notification servers, bots, and other projects using streams.
file
, token
, and follow
events previously only included the meta
field identifying the ID of the object that had been acted against. Now User Streams include the actual data from these events.
Files and tokens are included as the data
object. When someone follows or unfollows someone, both of their user streams would receive a follow
-type event with data
in this format:
{
"data": {
"followed_user": "...user object...",
"user": "...user object..."
}
}
Private message channels no longer have an "owner" or "creator" of the channel. The owner used to be in its own owner
field, and clients had to add that user to the list of users in the channel.acl.write.user_ids
. Now all users in the channel will be included in channel.acl.write.user_ids
, and the channel.user
and channel.user_id
will not be set at all.
This more accurately reflects the capabilities of the users in a private message, and removes a step or two from how clients parse them.
- The legacy poll response endpoint has been removed.
PUT /polls/{poll_id}/response/{position}
has been removed in favor of PUT /polls/{poll_id}/response
.
- Poll responses can be changed any time up until the poll closes.
An empty positions
will indicate to clear any responses for the user, but they will still be notified by E-mail when the poll closes, if they have the option enabled on https://pnut.io.
-
Poll responses cannot be viewed until after the poll closes.
-
GET /users/me/polls/responses
This endpoint returns a list of limited poll objects embedded with the authenticated user's responses to the polls. This change is just aligning the embedded poll objects more with normal poll objects:
The field poll.poll_id
has been renamed poll.id
, and the field poll.created_at
has been added in the response.
Raw objects had been a list of type
-value
pairs, like so:
[
{
"type": "io.pnut.core.oembed",
"value": {}
},
{
"type": "arbitrary_raw_type",
"value": {}
}
]
Now, there are lists of values for each type
, like so:
{
"io.pnut.core.oembed": [
{},
{}
],
"arbitrary_raw_type": [
{},
{}
]
}
User objects are included on many objects. There are a handful of cases where the user will not be available to be included on an object. For example, if the user is deleted, blocked, or the call has specified not to include the user, with a ?include_user=0
parameter.
In most of these cases, the user
field still exists on API v0
, with a value of the user's ID, instead of including the whole user object.
On v1
of the API, when a user is not included, the user
field will be absent and a separate user_id
field will be included.
Inversely, when ?include_limited_user=1
is set on channel calls, the user_ids
field will remain a list of the user IDs, and a separate users
field will be included.
User objects no longer include counts.users
.
The channel owner
field is now user
, to be in line with all other API objects.
The field is_sticky
is now always present on messages, even when false
.
These fields in the API have been changed from link
to url
:
source.link
on posts, messages, files, polls- the
link
in a link entity is nowurl
(butentities.links
is still "links") client.link
- post and message search terms
links
andlink_domains
are nowurls
andurl_domains
Users
verified.link
avatar_image.link
cover_image.link
Posts
GET /posts/explore
link
Files (and derived_files)
link
link_short
is nowurl_short
link_expires_at
is nowurl_expires_at
post.revision
, if included on the post, is now an integer instead of a string.
GET /sys/stats
The data returned is no longer a child of a counts
field.
counts.users.today
has been replaced with users.active
, listing the last 7 days' account totals that touched the API, not including the current day.
GET /sys/config
Removed:
- post.repost_max_length
Added:
- file.audio_max_size_bytes
- file.max_size_bytes
- post.seconds_for_revision
- user.name_max_length
- user.presence_max_length
Changed:
- rate_limit.anonymous.seconds_between_reset is now "read_reset_seconds"
- user.username_max_length was erroneously referring to the
name
max length, notusername
max length
POST /text/process
The entities are now placed within an entities
field, more like posts and other standard objects.
GET /channels/search
The field is_private
has been removed from channel search, and instead is_public
can be set to 1
, 0
, or not set at all.
GET /polls/search
The user_id
field has been changed to creator_id
on poll searches, to be consistent with other searches.
GET /posts/search
Searching posts without any parameters set will now return results. Previously, it would return an empty list, but now it is possible to effectively get a "Global" stream (with bot- and feed-type accounts included) from the search by not setting any filters or queries.
Also, if is_reply
is set to 0
now, results will only include posts that are not replies. Previously, this only mattered if set to 1
.
GET /users/search
The types
field on user search has been renamed user_types
like in other searches, for clarity and consistency.
User search no longer requires the q
field, and can return unbounded results, then. For example, you can now look up "all bots" without a search term.
Whether your app requests the basic
scope or not, it will now always be included if a user authorizes your app. This will not change what is actually allowed, but will add transparency around what your app can do when someone authorizes it.
Many endpoints' error messages have improved when a field is populated with the wrong type. Where previously it would simply say Wrong Type
, now usually it will say which field and type was wrong. Additionally, some resources, such as GET posts/{id}
, will now return a 400 error instead of a 404, if the wrong type is used for the lookup.
It used to be that reposting, replying to, or bookmarking a repost of a post would respond with a 400 error.
Now, these actions will automatically be done to the underlying post instead of erroring on the repost. It is still preferable for clients to act on the underlying post themselves, but this is smoothing out an issue newcomers may have to deal with.