social bookmarking for atproto
1{
2 "openapi": "3.1.1",
3 "info": {
4 "title": "Clippr AppView API",
5 "version": "1.0.1",
6 "description": "API reference documentation for Clippr's backend.",
7 "license": {
8 "name": "GNU Affero General Public License v3.0 only",
9 "identifier": "AGPL-3.0-only"
10 }
11 },
12 "servers": [
13 {
14 "url": "http://localhost:9090",
15 "description": "Development server"
16 },
17 {
18 "url": "https://api.clippr.social",
19 "description": "Production server"
20 }
21 ],
22 "tags": [
23 {
24 "name": "Clips",
25 "description": "API paths that relate to user bookmarks, or 'clips'."
26 },
27 {
28 "name": "Tags",
29 "description": "API paths that relate to user tags."
30 },
31 {
32 "name": "Profile",
33 "description": "API paths that relate to user profiles."
34 },
35 {
36 "name": "Misc",
37 "description": "API paths that don't fit into any other category."
38 }
39 ],
40 "paths": {
41 "/xrpc/social.clippr.actor.getPreferences": {
42 "get": {
43 "tags": ["Profile"],
44 "summary": "Get a user's preferences",
45 "operationId": "social.clippr.actor.getPreferences",
46 "description": "Get a user's private preferences. Requires authentication.",
47 "security": [
48 {
49 "Bearer": []
50 }
51 ],
52 "responses": {
53 "200": {
54 "description": "OK",
55 "content": {
56 "application/json": {
57 "schema": {
58 "$ref": "#/components/schemas/social.clippr.actor.defs.preferences"
59 }
60 }
61 }
62 },
63 "400": {
64 "description": "Bad Request",
65 "content": {
66 "application/json": {
67 "schema": {
68 "type": "object",
69 "properties": {
70 "error": {
71 "type": "string",
72 "description": "A general error code",
73 "oneOf": [
74 {
75 "const": "InvalidRequest"
76 },
77 {
78 "const": "ExpiredToken"
79 },
80 {
81 "const": "InvalidToken"
82 }
83 ]
84 },
85 "message": {
86 "type": "string",
87 "description": "A detailed description of the error"
88 }
89 }
90 }
91 }
92 }
93 },
94 "401": {
95 "description": "Unauthorized",
96 "content": {
97 "application/json": {
98 "schema": {
99 "type": "object",
100 "properties": {
101 "error": {
102 "type": "string",
103 "description": "A general error code",
104 "oneOf": [
105 {
106 "const": "AuthMissing"
107 }
108 ]
109 },
110 "message": {
111 "type": "string",
112 "description": "A detailed description of the error"
113 }
114 }
115 }
116 }
117 }
118 }
119 }
120 }
121 },
122 "/xrpc/social.clippr.actor.getProfile": {
123 "get": {
124 "tags": ["Profile"],
125 "summary": "Get a profile",
126 "operationId": "social.clippr.actor.getProfile",
127 "description": "Get a user's profile based on a given DID or handle.",
128 "parameters": [
129 {
130 "name": "actor",
131 "in": "query",
132 "description": "Handle or DID of account to fetch profile of",
133 "required": true,
134 "content": {
135 "schema": {
136 "type": "string",
137 "description": "Handle or DID of account to fetch profile of",
138 "format": "at-identifier"
139 }
140 },
141 "deprecated": false,
142 "allowEmptyValue": false
143 }
144 ],
145 "responses": {
146 "200": {
147 "description": "OK",
148 "content": {
149 "application/json": {
150 "schema": {
151 "type": "object",
152 "$ref": "#/components/schemas/social.clippr.actor.defs.profileView"
153 }
154 }
155 }
156 },
157 "400": {
158 "description": "Bad Request",
159 "content": {
160 "application/json": {
161 "schema": {
162 "type": "object",
163 "properties": {
164 "error": {
165 "type": "string",
166 "description": "A general error code",
167 "oneOf": [
168 {
169 "const": "InvalidRequest"
170 }
171 ]
172 },
173 "message": {
174 "type": "string",
175 "description": "A detailed description of the error"
176 }
177 }
178 }
179 }
180 }
181 }
182 }
183 }
184 },
185 "/xrpc/social.clippr.actor.putPreferences": {
186 "post": {
187 "tags": ["Profile"],
188 "summary": "Set a user's preferences",
189 "operationId": "social.clippr.actor.putPreferences",
190 "description": "Sets the private preferences attached to the account. Requires authentication.",
191 "security": [
192 {
193 "Bearer": []
194 }
195 ],
196 "requestBody": {
197 "required": true,
198 "content": {
199 "application/json": {
200 "schema": {
201 "type": "object",
202 "properties": {
203 "preferences": {
204 "$ref": "#/components/schemas/social.clippr.actor.defs.preferences"
205 }
206 }
207 }
208 }
209 }
210 },
211 "responses": {
212 "200": {
213 "description": "OK"
214 },
215 "400": {
216 "description": "Bad Request",
217 "content": {
218 "application/json": {
219 "schema": {
220 "type": "object",
221 "properties": {
222 "error": {
223 "type": "string",
224 "oneOf": [
225 {
226 "const": "InvalidRequest"
227 },
228 {
229 "const": "ExpiredToken"
230 },
231 {
232 "const": "InvalidToken"
233 }
234 ],
235 "description": "A general error code"
236 },
237 "message": {
238 "type": "string",
239 "description": "A detailed description of the error"
240 }
241 }
242 }
243 }
244 }
245 },
246 "401": {
247 "description": "Unauthorized",
248 "content": {
249 "application/json": {
250 "schema": {
251 "type": "object",
252 "properties": {
253 "error": {
254 "type": "string",
255 "description": "A general error code",
256 "oneOf": [
257 {
258 "const": "AuthMissing"
259 }
260 ]
261 },
262 "message": {
263 "type": "string",
264 "description": "A detailed description of the error"
265 }
266 }
267 }
268 }
269 }
270 }
271 }
272 }
273 },
274 "/xrpc/social.clippr.actor.searchClips": {
275 "get": {
276 "tags": ["Clips"],
277 "summary": "Search clips",
278 "operationId": "social.clippr.actor.searchClips",
279 "description": "Find clips matching search criteria.",
280 "parameters": [
281 {
282 "name": "q",
283 "in": "query",
284 "description": "Search query string",
285 "required": true,
286 "schema": {
287 "type": "string",
288 "description": "Search query string"
289 }
290 },
291 {
292 "name": "limit",
293 "in": "query",
294 "description": "How many clips to return in the query output",
295 "required": false,
296 "schema": {
297 "type": "integer",
298 "minimum": 1,
299 "maximum": 100,
300 "default": 25
301 }
302 },
303 {
304 "name": "actor",
305 "in": "query",
306 "description": "An actor to filter results to",
307 "required": false,
308 "schema": {
309 "type": "string",
310 "description": "An actor to filter results to",
311 "format": "at-identifier"
312 }
313 },
314 {
315 "name": "cursor",
316 "in": "query",
317 "description": "A parameter to paginate results",
318 "required": false,
319 "schema": {
320 "type": "string",
321 "description": "A parameter to paginate results"
322 }
323 }
324 ],
325 "responses": {
326 "200": {
327 "description": "OK",
328 "content": {
329 "application/json": {
330 "schema": {
331 "type": "object",
332 "properties": {
333 "cursor": {
334 "type": "string",
335 "description": "A parameter to paginate results"
336 },
337 "clips": {
338 "type": "array",
339 "items": {
340 "$ref": "#/components/schemas/social.clippr.feed.defs.clipView"
341 }
342 }
343 }
344 }
345 }
346 }
347 },
348 "400": {
349 "description": "Bad Request",
350 "content": {
351 "application/json": {
352 "schema": {
353 "type": "object",
354 "properties": {
355 "error": {
356 "type": "string",
357 "description": "A general error code",
358 "oneOf": [
359 {
360 "const": "InvalidRequest"
361 }
362 ]
363 },
364 "message": {
365 "type": "string",
366 "description": "A detailed description of the error"
367 }
368 }
369 }
370 }
371 }
372 }
373 }
374 }
375 },
376 "/xrpc/social.clippr.actor.searchProfiles": {
377 "get": {
378 "tags": ["Profile"],
379 "summary": "Search profiles",
380 "operationId": "social.clippr.actor.searchProfiles",
381 "description": "Find profiles matching search criteria.",
382 "parameters": [
383 {
384 "name": "q",
385 "in": "query",
386 "description": "Search query string",
387 "required": false,
388 "schema": {
389 "type": "string",
390 "description": "Search query string"
391 }
392 },
393 {
394 "name": "limit",
395 "in": "query",
396 "description": "The number of profiles to be returned in the query",
397 "required": false,
398 "schema": {
399 "type": "integer",
400 "minimum": 1,
401 "maximum": 100,
402 "default": 25
403 }
404 },
405 {
406 "name": "cursor",
407 "in": "query",
408 "description": "A parameter used for pagination",
409 "required": false,
410 "schema": {
411 "type": "string",
412 "description": "A parameter used for pagination"
413 }
414 }
415 ],
416 "responses": {
417 "200": {
418 "description": "OK",
419 "content": {
420 "application/json": {
421 "schema": {
422 "type": "object",
423 "properties": {
424 "cursor": {
425 "type": "string",
426 "description": "A parameter used for pagination"
427 },
428 "actors": {
429 "type": "array",
430 "items": {
431 "$ref": "#/components/schemas/social.clippr.actor.defs.profileView"
432 }
433 }
434 }
435 }
436 }
437 }
438 },
439 "400": {
440 "description": "Bad Request",
441 "content": {
442 "application/json": {
443 "schema": {
444 "type": "object",
445 "properties": {
446 "error": {
447 "type": "string",
448 "description": "A general error code",
449 "oneOf": [
450 {
451 "const": "InvalidRequest"
452 }
453 ]
454 },
455 "message": {
456 "type": "string",
457 "description": "A detailed description of the error"
458 }
459 }
460 }
461 }
462 }
463 }
464 }
465 }
466 },
467 "/xrpc/social.clippr.actor.searchTags": {
468 "get": {
469 "tags": ["Tags"],
470 "summary": "Search tags",
471 "operationId": "social.clippr.actor.searchTags",
472 "description": "Find tags matching search criteria.",
473 "parameters": [
474 {
475 "name": "q",
476 "in": "query",
477 "description": "Search query string",
478 "required": true,
479 "schema": {
480 "type": "string",
481 "description": "Search query string"
482 }
483 },
484 {
485 "name": "limit",
486 "in": "query",
487 "description": "How many tags to return in the query output",
488 "required": false,
489 "schema": {
490 "type": "integer",
491 "minimum": 1,
492 "maximum": 100,
493 "default": 25
494 }
495 },
496 {
497 "name": "actor",
498 "in": "query",
499 "description": "An actor to filter results to",
500 "required": false,
501 "schema": {
502 "type": "string",
503 "description": "An actor to filter results to",
504 "format": "at-identifier"
505 }
506 },
507 {
508 "name": "cursor",
509 "in": "query",
510 "description": "A parameter to paginate results",
511 "required": false,
512 "schema": {
513 "type": "string",
514 "description": "A parameter to paginate results"
515 }
516 }
517 ],
518 "responses": {
519 "200": {
520 "description": "OK",
521 "content": {
522 "application/json": {
523 "schema": {
524 "type": "object",
525 "properties": {
526 "cursor": {
527 "type": "string",
528 "description": "A parameter to paginate results"
529 },
530 "tags": {
531 "type": "array",
532 "items": {
533 "$ref": "#/components/schemas/social.clippr.feed.defs.tagView"
534 }
535 }
536 }
537 }
538 }
539 }
540 },
541 "400": {
542 "description": "Bad Request",
543 "content": {
544 "application/json": {
545 "schema": {
546 "type": "object",
547 "properties": {
548 "error": {
549 "type": "string",
550 "description": "A general error code",
551 "oneOf": [
552 {
553 "const": "InvalidRequest"
554 }
555 ]
556 },
557 "message": {
558 "type": "string",
559 "description": "A detailed description of the error"
560 }
561 }
562 }
563 }
564 }
565 }
566 }
567 }
568 },
569 "/xrpc/social.clippr.feed.getClips": {
570 "get": {
571 "tags": ["Clips"],
572 "summary": "Get clips",
573 "operationId": "social.clippr.feed.getClips",
574 "description": "Get the hydrated views of a list of clips from their AT URIs.",
575 "parameters": [
576 {
577 "name": "uris",
578 "in": "query",
579 "description": "List of tag AT-URIs to return hydrated views for",
580 "required": true,
581 "schema": {
582 "type": "array",
583 "items": {
584 "type": "string",
585 "format": "at-uri"
586 },
587 "maxItems": 25
588 }
589 }
590 ],
591 "responses": {
592 "200": {
593 "description": "OK",
594 "content": {
595 "application/json": {
596 "schema": {
597 "type": "array",
598 "items": {
599 "$ref": "#/components/schemas/social.clippr.feed.defs.clipView"
600 }
601 }
602 }
603 }
604 },
605 "400": {
606 "description": "Bad Request",
607 "content": {
608 "application/json": {
609 "schema": {
610 "type": "object",
611 "properties": {
612 "error": {
613 "type": "string",
614 "description": "A general error code",
615 "oneOf": [
616 {
617 "const": "InvalidRequest"
618 }
619 ]
620 },
621 "message": {
622 "type": "string",
623 "description": "A detailed description of the error"
624 }
625 }
626 }
627 }
628 }
629 }
630 }
631 }
632 },
633 "/xrpc/social.clippr.feed.getTags": {
634 "get": {
635 "tags": ["Tags"],
636 "summary": "Get tags",
637 "operationId": "social.clippr.feed.getTags",
638 "description": "Get a the hydrated views of a list of tags from their AT URIs.",
639 "parameters": [
640 {
641 "name": "uris",
642 "in": "query",
643 "description": "List of tag AT-URIs to return hydrated views for",
644 "required": true,
645 "schema": {
646 "type": "array",
647 "items": {
648 "type": "string",
649 "format": "at-uri"
650 },
651 "maxItems": 25
652 }
653 }
654 ],
655 "responses": {
656 "200": {
657 "description": "OK",
658 "content": {
659 "application/json": {
660 "schema": {
661 "type": "array",
662 "items": {
663 "$ref": "#/components/schemas/social.clippr.feed.defs.tagView"
664 }
665 }
666 }
667 }
668 },
669 "400": {
670 "description": "Bad Request",
671 "content": {
672 "application/json": {
673 "schema": {
674 "type": "object",
675 "properties": {
676 "error": {
677 "type": "string",
678 "description": "A general error code",
679 "oneOf": [
680 {
681 "const": "InvalidRequest"
682 }
683 ]
684 },
685 "message": {
686 "type": "string",
687 "description": "A detailed description of the error"
688 }
689 }
690 }
691 }
692 }
693 }
694 }
695 }
696 },
697 "/xrpc/social.clippr.feed.getProfileClips": {
698 "get": {
699 "tags": ["Clips"],
700 "summary": "Get a profile's clip feed",
701 "operationId": "social.clippr.feed.getProfileClips",
702 "description": "Get a view of a profile's reverse-chronological clips feed.",
703 "parameters": [
704 {
705 "name": "actor",
706 "in": "query",
707 "description": "An actor to get feed data from",
708 "required": true,
709 "schema": {
710 "type": "string",
711 "description": "An actor to get feed data from",
712 "format": "at-identifier"
713 }
714 },
715 {
716 "name": "limit",
717 "in": "query",
718 "description": "How many results to return with the query",
719 "required": false,
720 "schema": {
721 "type": "integer",
722 "minimum": 1,
723 "maximum": 100,
724 "default": 50
725 }
726 },
727 {
728 "name": "cursor",
729 "in": "query",
730 "description": "A parameter to paginate results",
731 "required": false,
732 "schema": {
733 "type": "string",
734 "description": "A parameter to paginate results"
735 }
736 },
737 {
738 "name": "filter",
739 "in": "query",
740 "description": "What types to include in response",
741 "required": false,
742 "schema": {
743 "type": "string",
744 "description": "What types of clips to include in response",
745 "default": "all_clips",
746 "enum": ["all_clips", "tagged_clips", "untagged_clips"]
747 }
748 }
749 ],
750 "responses": {
751 "200": {
752 "description": "OK",
753 "content": {
754 "application/json": {
755 "schema": {
756 "type": "object",
757 "properties": {
758 "cursor": {
759 "type": "string"
760 },
761 "feed": {
762 "type": "array",
763 "items": {
764 "$ref": "#/components/schemas/social.clippr.feed.defs.clipView"
765 }
766 }
767 }
768 }
769 }
770 }
771 },
772 "400": {
773 "description": "Bad Request",
774 "content": {
775 "application/json": {
776 "schema": {
777 "type": "object",
778 "properties": {
779 "error": {
780 "type": "string",
781 "description": "A general error code",
782 "oneOf": [
783 {
784 "const": "InvalidRequest"
785 }
786 ]
787 },
788 "message": {
789 "type": "string",
790 "description": "A detailed description of the error"
791 }
792 }
793 }
794 }
795 }
796 }
797 }
798 }
799 },
800 "/xrpc/social.clippr.feed.getProfileTags": {
801 "get": {
802 "tags": ["Tags"],
803 "summary": "Get a profile's tag feed",
804 "operationId": "social.clippr.feed.getProfileTags",
805 "description": "Get a view of a profile's reverse-chronological clips feed.",
806 "parameters": [
807 {
808 "name": "actor",
809 "in": "query",
810 "description": "An actor to get feed data from",
811 "required": true,
812 "schema": {
813 "type": "string",
814 "description": "An actor to get feed data from",
815 "format": "at-identifier"
816 }
817 },
818 {
819 "name": "limit",
820 "in": "query",
821 "description": "How many results to return with the query",
822 "required": false,
823 "schema": {
824 "type": "integer",
825 "minimum": 1,
826 "maximum": 100,
827 "default": 50
828 }
829 },
830 {
831 "name": "cursor",
832 "in": "query",
833 "description": "A parameter to paginate results",
834 "required": false,
835 "schema": {
836 "type": "string",
837 "description": "A parameter to paginate results"
838 }
839 }
840 ],
841 "responses": {
842 "200": {
843 "description": "OK",
844 "content": {
845 "application/json": {
846 "schema": {
847 "type": "object",
848 "properties": {
849 "cursor": {
850 "type": "string"
851 },
852 "feed": {
853 "type": "array",
854 "items": {
855 "$ref": "#/components/schemas/social.clippr.feed.defs.tagView"
856 }
857 }
858 }
859 }
860 }
861 }
862 },
863 "400": {
864 "description": "Bad Request",
865 "content": {
866 "application/json": {
867 "schema": {
868 "type": "object",
869 "properties": {
870 "error": {
871 "type": "string",
872 "description": "A general error code",
873 "oneOf": [
874 {
875 "const": "InvalidRequest"
876 }
877 ]
878 },
879 "message": {
880 "type": "string",
881 "description": "A detailed description of the error"
882 }
883 }
884 }
885 }
886 }
887 }
888 }
889 }
890 },
891 "/xrpc/social.clippr.feed.getTagList": {
892 "get": {
893 "tags": ["Tags"],
894 "summary": "Get a profile's tag list",
895 "operationId": "social.clippr.feed.getProfileTags",
896 "description": "Get a profile's complete list of tags.",
897 "parameters": [
898 {
899 "name": "actor",
900 "in": "query",
901 "description": "An actor to fetch the tag list from",
902 "required": false,
903 "schema": {
904 "type": "string",
905 "description": "An actor to fetch the tag list from",
906 "format": "at-identifier"
907 }
908 }
909 ],
910 "responses": {
911 "200": {
912 "description": "OK",
913 "content": {
914 "application/json": {
915 "schema": {
916 "type": "object",
917 "properties": {
918 "tags": {
919 "type": "array",
920 "items": {
921 "$ref": "#/components/schemas/social.clippr.feed.defs.tagView"
922 }
923 }
924 }
925 }
926 }
927 }
928 },
929 "400": {
930 "description": "Bad Request",
931 "content": {
932 "application/json": {
933 "schema": {
934 "type": "object",
935 "properties": {
936 "error": {
937 "type": "string",
938 "description": "A general error code",
939 "oneOf": [
940 {
941 "error": "InvalidRequest"
942 }
943 ]
944 },
945 "message": {
946 "type": "string",
947 "description": "A detailed description of the error"
948 }
949 }
950 }
951 }
952 }
953 }
954 }
955 }
956 },
957 "/xrpc/_health": {
958 "get": {
959 "summary": "Health check",
960 "description": "Check the health of the server. If it is functioning properly, you will receive the server's version number.",
961 "responses": {
962 "200": {
963 "description": "OK",
964 "content": {
965 "application/json": {
966 "schema": {
967 "type": "object",
968 "properties": {
969 "version": {
970 "type": "string",
971 "description": "The version number of the AppView."
972 }
973 }
974 }
975 }
976 }
977 }
978 },
979 "tags": ["Misc"]
980 }
981 }
982 },
983 "components": {
984 "schemas": {
985 "com.atproto.repo.strongRef": {
986 "type": "object",
987 "required": ["uri", "cid"],
988 "properties": {
989 "uri": {
990 "type": "string",
991 "format": "at-uri"
992 },
993 "cid": {
994 "type": "string",
995 "format": "cid"
996 }
997 }
998 },
999 "social.clippr.actor.defs.profileView": {
1000 "type": "object",
1001 "description": "A view of an actor's profile",
1002 "required": ["did", "handle", "displayName"],
1003 "properties": {
1004 "did": {
1005 "type": "string",
1006 "description": "The DID of the profile",
1007 "format": "did"
1008 },
1009 "handle": {
1010 "type": "string",
1011 "description": "The handle of the profile",
1012 "format": "handle"
1013 },
1014 "displayName": {
1015 "type": "string",
1016 "description": "The display name associated to the profile",
1017 "maxLength": 64
1018 },
1019 "description": {
1020 "type": "string",
1021 "description": "The biography associated to the profile",
1022 "maxLength": 500
1023 },
1024 "avatar": {
1025 "type": "string",
1026 "description": "A link to the profile's avatar",
1027 "format": "uri"
1028 },
1029 "createdAt": {
1030 "type": "string",
1031 "description": "When the profile record was first created",
1032 "format": "date-time"
1033 }
1034 }
1035 },
1036 "social.clippr.actor.defs.preferences": {
1037 "type": "array",
1038 "items": {
1039 "oneOf": [
1040 {
1041 "$ref": "#/components/schemas/social.clippr.actor.defs.publishingScopesPref"
1042 }
1043 ]
1044 }
1045 },
1046 "social.clippr.actor.defs.publishingScopesPref": {
1047 "type": "object",
1048 "description": "Preferences for a user's publishing scopes",
1049 "required": ["defaultScope"],
1050 "properties": {
1051 "defaultScope": {
1052 "type": "string",
1053 "description": "What publishing scope to mark a clip as by default",
1054 "enum": ["public", "unlisted"]
1055 }
1056 }
1057 },
1058 "social.clippr.feed.defs.clipView": {
1059 "type": "object",
1060 "description": "A view of a single bookmark (or 'clip')",
1061 "required": ["uri", "cid", "author", "record", "indexedAt"],
1062 "properties": {
1063 "uri": {
1064 "type": "string",
1065 "description": "The AT-URI of the clip",
1066 "format": "at-uri"
1067 },
1068 "cid": {
1069 "type": "string",
1070 "description": "The CID of the clip",
1071 "format": "cid"
1072 },
1073 "author": {
1074 "description": "A reference to the actor's profile",
1075 "$ref": "#/components/schemas/social.clippr.actor.defs.profileView"
1076 },
1077 "record": {
1078 "type": "object",
1079 "description": "The raw record of the clip"
1080 },
1081 "indexedAt": {
1082 "type": "string",
1083 "description": "The time in which the clip's record was indexed by the AppView",
1084 "format": "date-time"
1085 }
1086 }
1087 },
1088 "social.clippr.feed.defs.tagView": {
1089 "type": "object",
1090 "description": "A view of a single tag",
1091 "required": ["uri", "cid", "author", "record", "indexedAt"],
1092 "properties": {
1093 "uri": {
1094 "type": "string",
1095 "description": "The AT-URI to the tag",
1096 "format": "at-uri"
1097 },
1098 "cid": {
1099 "type": "string",
1100 "description": "The CID of the tag",
1101 "format": "cid"
1102 },
1103 "author": {
1104 "description": "A reference to the actor's profile",
1105 "$ref": "#/components/schemas/social.clippr.actor.defs.profileView"
1106 },
1107 "record": {
1108 "type": "object",
1109 "description": "The raw record of the clip"
1110 },
1111 "indexedAt": {
1112 "type": "string",
1113 "description": "The time in which the tag's record was indexed by the AppView",
1114 "format": "date-time"
1115 }
1116 }
1117 },
1118 "social.clippr.actor.profile": {
1119 "type": "object",
1120 "required": ["createdAt", "displayName"],
1121 "properties": {
1122 "displayName": {
1123 "type": "string",
1124 "description": "A display name to be shown on a profile",
1125 "maxLength": 64
1126 },
1127 "description": {
1128 "type": "string",
1129 "description": "Text for user to describe themselves",
1130 "maxLength": 500
1131 },
1132 "avatar": {
1133 "type": "blob",
1134 "maxSize": 1000000,
1135 "description": "Image to show on user's profiles"
1136 },
1137 "createdAt": {
1138 "type": "string",
1139 "description": "The creation date of the profile",
1140 "format": "date-time"
1141 }
1142 }
1143 },
1144 "social.clippr.feed.clip": {
1145 "type": "object",
1146 "required": ["url", "title", "description", "unlisted", "createdAt"],
1147 "properties": {
1148 "url": {
1149 "type": "string",
1150 "description": "The URL of the bookmark. Cannot be left empty or be modified after creation.",
1151 "format": "uri",
1152 "maxLength": 2000
1153 },
1154 "title": {
1155 "type": "string",
1156 "description": "The title of the bookmark. If left empty, reuse the URL.",
1157 "maxLength": 2048
1158 },
1159 "description": {
1160 "type": "string",
1161 "description": "A description of the bookmark's content. This should be ripped from the URL metadata and be static for all records using the URL.",
1162 "maxLength": 4096
1163 },
1164 "notes": {
1165 "type": "string",
1166 "description": "User-written notes for the bookmark. Public and personal.",
1167 "maxLength": 10000
1168 },
1169 "tags": {
1170 "type": "array",
1171 "description": "An array of tags. A format of solely alphanumeric characters and dashes should be used.",
1172 "items": {
1173 "$ref": "#/components/schemas/com.atproto.repo.strongRef"
1174 }
1175 },
1176 "unlisted": {
1177 "type": "boolean",
1178 "description": "Whether the bookmark can be used for feed indexing and aggregation"
1179 },
1180 "unread": {
1181 "type": "boolean",
1182 "description": "Whether the bookmark has been read by the user",
1183 "default": true
1184 },
1185 "languages": {
1186 "type": "array",
1187 "items": {
1188 "type": "string",
1189 "format": "language"
1190 },
1191 "maxItems": 5
1192 },
1193 "createdAt": {
1194 "type": "string",
1195 "description": "Client-declared timestamp when the bookmark is created",
1196 "format": "date-time"
1197 }
1198 }
1199 },
1200 "social.clippr.feed.tag": {
1201 "type": "object",
1202 "required": ["name", "createdAt"],
1203 "properties": {
1204 "name": {
1205 "type": "string",
1206 "description": "A de-duplicated string containing the name of the tag",
1207 "maxLength": 64
1208 },
1209 "color": {
1210 "type": "string",
1211 "description": "A hexadecimal color code",
1212 "maxLength": 7
1213 },
1214 "description": {
1215 "type": "string",
1216 "description": "A description of the tag for additional context",
1217 "maxLength": 5000
1218 },
1219 "createdAt": {
1220 "type": "string",
1221 "description": "A client-defined timestamp for the creation of the tag",
1222 "format": "date-time"
1223 }
1224 }
1225 }
1226 }
1227 }
1228}