Skip to content
Gary Jones edited this page Apr 24, 2026 · 1 revision

Co-Authors Plus registers two families of REST endpoints under the coauthors/v1 namespace. The newer /coauthors/v1/coauthors routes follow WordPress's core REST conventions (snake_case, schemas, publish-aware permissions) and are the ones to reach for when building a front-end, a block, or an external integration. The older /coauthors/v1/authors* and /coauthors/v1/search routes power the plugin's own admin UI and use a camelCase ad-hoc response shape.

This page covers both, and closes with a short note on the core coauthors field added to /wp/v2/posts/{id} responses.

/coauthors/v1/coauthors

The canonical read endpoint. Use this when you need a post's byline from JavaScript, a headless site, or any external caller.

Get co-authors for a post

  • Method: GET
  • Route: /coauthors/v1/coauthors?post_id={id}
  • Authentication: not required when the post is publicly viewable; requires read_post capability otherwise.

Query parameters:

Name Type Required Description
post_id integer yes ID of the post whose co-authors to return.

Returns an array of co-author objects matching the schema below. Errors with rest_post_invalid_id (404) if the post doesn't exist, or rest_forbidden (401/403) if the post is not viewable and the caller cannot read it.

Get a single co-author

  • Method: GET
  • Route: /coauthors/v1/coauthors/{user_nicename}
  • Authentication: not required when the co-author has at least one publicly-viewable post; otherwise requires the coauthors_plus_edit_authors capability (equivalent to edit_others_posts by default).

Path parameters:

Name Type Required Description
user_nicename string yes The co-author's slug (user_nicename). Sanitised with sanitize_title().

Returns a single co-author object. Errors with rest_forbidden if the co-author has no public posts and the caller lacks the required capability.

Response schema

Both routes return objects (or arrays of objects) of this shape:

{
  "id": 42,
  "display_name": "Ada Lovelace",
  "description": {
    "raw": "First programmer.",
    "rendered": "<p>First programmer.</p>"
  },
  "user_nicename": "ada-lovelace",
  "link": "https://example.com/author/ada-lovelace/",
  "featured_media": 108,
  "avatar_urls": {
    "24": "",
    "48": "",
    "96": ""
  }
}

Field notes:

  • id — the underlying WordPress user ID (for mapped/unmapped users) or the guest-author post ID.
  • description.raw — only populated for requesters who pass the capability check filtered by coauthors_rest_view_description_cap (default edit_posts). Lower-cap users receive an empty string. The rendered form is always empty unless raw is populated.
  • link — the public author archive URL.
  • featured_media — the attachment ID of the guest author's avatar override, or 0 if unset. Only meaningful for guest authors.
  • avatar_urls — only present when the site has show_avatars enabled. For guest authors the returned URLs use the guest-author featured image where one is set, otherwise fall back to Gravatar using the author's configured email.

The schema is filterable via rest_coauthors_item_schema — see Hooks and filters. Adding new top-level properties through that filter will trigger a _doing_it_wrong warning; use it to adjust existing fields, not to extend them. For response-level mutation use rest_prepare_coauthor, which mirrors core's rest_prepare_{post_type} pattern.

/coauthors/v1/authors/* (plugin UI endpoints)

These routes power the co-author picker inside the post editor. They are authenticated against current_user_can_set_authors(), use a camelCase response shape, and are fair game to call from your own admin UIs — but prefer the canonical endpoint above for public or front-end work.

Search co-authors

  • Method: GET
  • Route: /coauthors/v1/search
  • Authentication: current_user_can_set_authors() — by default, editors and above.

Query parameters:

Name Type Required Description
q string no Free-text search. Matched against display name, login, nicename and email.
existing_authors string no Comma-separated list of user_login values to exclude from results. Used by the picker to hide authors that are already assigned.

Get co-authors for a post

  • Method: GET
  • Route: /coauthors/v1/authors/{post_id}
  • Authentication: current_user_can_set_authors().

Returns [] (empty array) for the wp_block post type and for REST requests originating from the pattern-sync flow, because neither benefits from co-author rendering.

Resolve co-authors by term IDs

  • Method: GET
  • Route: /coauthors/v1/authors-by-term-ids
  • Authentication: current_user_can_set_authors().

Query parameters:

Name Type Required Description
ids string yes Comma-separated list of author taxonomy term IDs.

Added in 4.0.0 to support the core entity store in the block editor: the editor knows the author-taxonomy term IDs assigned to a post and uses this endpoint to resolve them to rich author data in a single request.

Update co-authors on a post

  • Method: POST
  • Route: /coauthors/v1/authors/{post_id}
  • Authentication: current_user_can_set_authors().

Body parameters:

Name Type Required Description
new_authors string no Comma-separated list of user_nicename values. Replaces the post's current co-authors wholesale.

Returns the post's updated co-author list in the response, so the UI can re-render without a follow-up fetch.

Response shape for the UI endpoints

{
  "id": "42",
  "termId": 17,
  "userNicename": "ada-lovelace",
  "login": "ada",
  "email": "ada@example.com",
  "displayName": "Ada Lovelace",
  "avatar": "https://example.com/wp-content/uploads/ada.jpg",
  "userType": "guest-author"
}

Note the casing difference from the canonical endpoint. These fields exist for historical reasons and aren't schema-filtered.

Coauthor data on /wp/v2/posts and /wp/v2/{post_type}

Since 4.0.0, Co-Authors Plus registers its author taxonomy with the REST API, so every post response on the core post endpoints carries an extra coauthors field containing the assigned author taxonomy term IDs.

{
  "id": 123,
  "title": { "rendered": "Hello" },
  "author": 5,
  "coauthors": [17, 24],
  "…": ""
}

To resolve term IDs to rich author data, call /coauthors/v1/authors-by-term-ids?ids=17,24.

Important for integrations. If you filter the response with _fields, include coauthors if you need them — otherwise the field is simply absent from the payload. (4.0.0 shipped a bug where a missing coauthors in a narrowed response caused the plugin to overwrite the post's co-authors with post_author. That filter was removed in 4.0.1; see Recovering from the 4.0.0 REST backfill regression if your site ran 4.0.0.)

Authentication notes

For server-to-server integrations:

  • Application passwords (WordPress 5.6+) are the recommended way to authenticate against any of these endpoints.
  • Cookie + nonce works for same-origin JavaScript clients.
  • Unauthenticated access works only for reads where the post and author are already public, per the rules above.

Extending the response

To add fields to the canonical endpoint's responses, hook rest_prepare_coauthor:

add_filter( 'rest_prepare_coauthor', function ( $response, $author, $request ) {
    $data                     = $response->get_data();
    $data['twitter_handle']   = get_post_meta( $author->ID, 'twitter_handle', true );
    $response->set_data( $data );
    return $response;
}, 10, 3 );

If you want the new field to appear in OPTIONS schema output as well, pair that with an entry on rest_coauthors_item_schema:

add_filter( 'rest_coauthors_item_schema', function ( $schema ) {
    // Note: adding top-level properties here triggers _doing_it_wrong in CAP.
    // Prefer register_rest_field() or extending an existing property.
    return $schema;
} );

For anything more invasive, consider registering a sibling endpoint rather than mutating the core one.