GravityBoard hooks and REST API
GravityBoard provides hooks that developers can use to extend or modify its functionality. Each section below shows the hook’s PHPDoc from the plugin source, with some types simplified, followed by the exact do_action() or apply_filters() call. Versions listed in @since tags refer to GravityBoard releases.
Actions #
Assignee actions
gk/gravityboard/assignees/added
/**
* Fired when a user is assigned to an entry via the GravityBoard interface.
*
* @since 1.0
*
* @param int $user_id The ID of the user who was assigned.
* @param int $entry_id The ID of the entry that was updated.
* @param array $feed The feed associated with the board.
* @param array $form The form associated with the entry.
*/
do_action( 'gk/gravityboard/assignees/added', (int) $user_id, $entry_id, $feed, $form );gk/gravityboard/assignees/removed
/**
* Fired when a user is unassigned from an entry via the GravityBoard interface.
*
* @since 1.0
*
* @param int $user_id The ID of the user who was unassigned.
* @param int $entry_id The ID of the entry that was updated.
* @param array $feed The feed associated with the board.
* @param array $form The form associated with the entry.
*/
do_action( 'gk/gravityboard/assignees/removed', (int) $user_id, $entry_id, $feed, $form );gk/gravityboard/assignees/updated
/**
* Fired after entry assignees are successfully updated.
*
* @since 1.0
*
* @param int $entry_id The ID of the entry that was updated.
* @param int[] $assignees The user IDs assigned to the entry.
* @param FeedArray $feed The feed associated with the board.
* @param array<string, mixed> $form The Gravity Forms form associated with the entry.
*/
do_action( 'gk/gravityboard/assignees/updated', (int) $entry_id, $assignees, $feed, $form );Attachment actions
gk/gravityboard/attachments/added
/**
* Runs when attachments have been added, before the notification is triggered.
*
* @since 1.0
*
* @param array $attachments The attachments array.
* @param array $entry The entry array.
* @param array $feed The feed array.
*/
do_action( 'gk/gravityboard/attachments/added', $attachments, $entry, $feed );gk/gravityboard/attachments/removed
/**
* Runs when attachments have been removed, before the notification is triggered.
*
* @since 1.0
*
* @param Attachment[] $updated_attachments The attachments remaining on the entry. Keys are gapped: the deleted row is filtered out without re-indexing.
* @param array<string, mixed> $entry The Gravity Forms entry.
* @param FeedArray $feed The board's feed.
* @param string $attachment_id_to_delete The ID of the attachment that was deleted.
*/
do_action( 'gk/gravityboard/attachments/removed', $updated_attachments, $entry, $feed, $attachment_id_to_delete );gk/gravityboard/attachments/updated
/**
* Runs when attachments have been updated, before the notification is triggered.
*
* @since 1.0
*
* @param array $sanitized_attachments The sanitized attachments array.
* @param array $entry The entry array.
* @param array $feed The feed array.
*/
do_action( 'gk/gravityboard/attachments/updated', $sanitized_attachments, $entry, $feed );Card actions
gk/gravityboard/card/added
/**
* Runs when a card (entry) has been created, before the notification is triggered.
*
* @since 1.0
*
* @param array $created_entry The created entry data.
* @param array $feed The feed data.
* @param WP_REST_Request $request The REST request object.
*/
do_action( 'gk/gravityboard/card/added', $created_entry, $feed, $request );gk/gravityboard/card/edited
/**
* Runs when a card (entry) has been updated, before the notification is triggered.
*
* @since 1.0
*
* @param array $updated_entry The updated entry data.
* @param array $feed The feed data.
* @param array $changes The changes to the card; each element is a string of the field or meta key that was updated.
*/
do_action( 'gk/gravityboard/card/edited', $updated_entry, $feed, $changes );gk/gravityboard/card/changed-lane
/**
* Runs when a card (entry) has been moved to a new lane, before the notification is triggered.
*
* @since 1.0
*
* @param array<string, mixed> $updated_entry The updated entry, keyed by field ID alongside the entry properties.
* @param FeedRow $feed The feed.
* @param string|int|null $source_lane_id The source lane ID exactly as the request sent it, or null when the request named none. From a card save, the lane the card's value named, or null when it named none.
* @param int $target_lane_id The ID of the target lane.
*/
do_action( 'gk/gravityboard/card/changed-lane', $updated_entry, $feed, $source_lane_id, $target_lane_id );This action also fires when a card save changes the field the board uses for lanes. A save that changes only that field fires this action and not gk/gravityboard/card/edited.
gk/gravityboard/card/sorted
/**
* Runs when a card (entry) has been sorted, before the notification is triggered.
*
* @since 1.0
*
* @param array<string, mixed> $updated_entry The updated entry, keyed by field ID alongside the entry properties.
* @param FeedRow $feed The feed.
* @param string|int|null $source_lane_id The sorted lane's ID exactly as the request sent it, or null when the request named none.
* @param int[] $ordered_ids The card IDs the request sent, top first, narrowed to the feed's form, the target lane and the cards the user may see. An ID's index is its place in that list, not its stored position number.
*/
do_action( 'gk/gravityboard/card/sorted', $updated_entry, $feed, $source_lane_id, $hook_ids );This action does not fire when a card is dragged within its lane on a board with Enable Voting and Sort Cards by Votes on. The board keeps its vote order, so the drag saves nothing.
gk/gravityboard/card/deleted
/**
* Runs when a card (entry) has been trashed or deleted, before the notification is triggered.
*
* @since 1.0
*
* @param array<string, mixed> $entry The entry as it was before deletion, keyed by field ID alongside the entry properties.
* @param FeedRow $feed The feed.
* @param string $deletion_mode The deletion mode ("trash" or "delete").
*/
do_action( 'gk/gravityboard/card/deleted', $entry, $feed, $deletion_mode );Checklist actions
gk/gravityboard/checklists/updated
/**
* Runs when checklists have been updated.
*
* @since 1.1
*
* @param ChecklistCollection $checklists The checklist collection.
* @param array $entry The entry array.
* @param array $feed The feed array.
*/
do_action( 'gk/gravityboard/checklists/updated', $checklists, $entry, $feed );gk/gravityboard/checklists/item/added
/**
* Runs when a checklist item has been added.
*
* @since 1.1
*
* @param array|WP_Error $entry The entry data, or a WP_Error if the entry is not found.
* @param ChecklistItem $new_item The new checklist item.
* @param array $feed The feed data.
*/
do_action( 'gk/gravityboard/checklists/item/added', Helpers::get_card( $entry_id ), $new_item, $feed );gk/gravityboard/checklists/item/updated
/**
* Runs when a checklist item has been updated.
*
* @since 1.1
*
* @param array|WP_Error $entry The entry data, or a WP_Error if the entry is not found.
* @param ChecklistItem $item The checklist item.
* @param ChecklistCollection $collection The updated checklists collection.
* @param array $feed The feed data.
*/
do_action( 'gk/gravityboard/checklists/item/updated', Helpers::get_card( $entry_id ), $item, $checklist_collection, $feed );gk/gravityboard/checklists/item/deleted
/**
* Runs when a checklist item has been deleted.
*
* @since 1.1
*
* @param array|WP_Error $entry The entry data, or a WP_Error if the entry is not found.
* @param ChecklistItem $item The deleted checklist item.
* @param ChecklistCollection $checklists The updated checklists data.
* @param array $feed The feed data.
*/
do_action( 'gk/gravityboard/checklists/item/deleted', Helpers::get_card( $entry_id ), $item, $collection, $feed );gk/gravityboard/checklists/templates-applied
/**
* Runs when checklist templates have been applied to an entry.
*
* @since 1.1
*
* @param ChecklistCollection $merged_collection The merged template collection that was applied.
* @param array<string, mixed> $entry The Gravity Forms entry that was created.
* @param list<int|string> $applied_feed_ids The IDs of the feeds whose templates were applied.
* @param array<string, mixed> $form The Gravity Forms form.
* @param int $items_added Number of items added from templates.
*/
do_action( 'gk/gravityboard/checklists/templates-applied', $merged_collection, $entry, $applied_feed_ids, $form, $items_added );Lane actions
gk/gravityboard/lane/added
/**
* Runs when a lane has been added.
*
* @since 1.0
*
* @param int $new_lane_id The ID of the new lane.
* @param array<string, mixed> $new_lane_choice The new lane choice: `text`, `value`, `isSelected`, `price`.
* @param FeedRow $feed The feed data.
*/
do_action( 'gk/gravityboard/lane/added', $new_lane_id, $new_lane_choice, $this->feed );gk/gravityboard/lane/edited
/**
* Runs when a lane has been edited.
*
* @since 1.0
*
* @param array $form The form data.
* @param int $lane_field_id The ID of the lane field.
* @param array $feed The feed data.
*/
do_action( 'gk/gravityboard/lane/edited', $this->form, $this->lane_field->id, $this->feed );gk/gravityboard/lane/moved
/**
* Runs when a lane has been moved.
*
* @since 1.0
*
* @param array $form The form data.
* @param int $lane_field_id The ID of the lane field.
* @param array $feed The feed data.
* @param int $new_position The new position of the lane.
*/
do_action( 'gk/gravityboard/lane/moved', $this->form, $this->lane_field->id, $this->feed, $new_position );gk/gravityboard/lane/deleted
/**
* Runs when a lane has been deleted.
*
* @since 1.0
*
* @param array $form The form data.
* @param int $lane_field_id The ID of the lane field.
* @param array $feed The feed data.
* @param int $lane_id The ID of the lane that was deleted.
*/
do_action( 'gk/gravityboard/lane/deleted', $this->form, $this->lane_field->id, $this->feed, $lane_id );Voting actions
gk/gravityboard/voting/vote-added
/**
* Fired when a user's vote is added on a card.
*
* @since 1.4.0
*
* @param int $entry_id The entry (card) ID.
* @param int $user_id The voting user ID.
* @param int $feed_id The feed ID.
* @param int $new_weight The resulting vote weight.
*/
do_action( 'gk/gravityboard/voting/vote-added', $entry_id, $user_id, $feed_id, $new_weight );gk/gravityboard/voting/vote-removed
/**
* Fired when a user's vote is removed from a card.
*
* @since 1.4.0
*
* @param int $entry_id The entry (card) ID.
* @param int $user_id The voting user ID.
* @param int $feed_id The feed ID.
* @param int $new_weight The resulting vote weight after removal.
*/
do_action( 'gk/gravityboard/voting/vote-removed', $entry_id, $user_id, $feed_id, $new_weight );AJAX actions
gk/gravityboard/ajax/register-routes
/**
* Allow other plugins to register REST routes on the GravityBoard Ajax instance.
*
* @since 1.0.0
*
* @param Ajax $ajax The Ajax instance.
*/
do_action( 'gk/gravityboard/ajax/register-routes', $this );Filters #
Card and data filters
gk/gravityboard/card/data
/**
* Filter the card data returned from the entry.
*
* @since 1.1
*
* @param array $card The card data.
* @param array $entry The entry data.
* @param array $feed The feed data.
*
* @return array
*/
return apply_filters( 'gk/gravityboard/card/data', $card, $entry, $feed );gk/gravityboard/card/update-card
/**
* Allow plugins to add additional changes to the card.
*
* `Card::update_from_request()` above has already saved the core fields by the time this
* runs, and there is no transaction to roll it back with. A callback that returns a
* WP_Error therefore fails the request, not the save: the core fields it names stay
* persisted, and this method merges them into the WP_Error's data under
* `persisted_changes` before returning it, so a caller can reconcile rather than assume
* nothing was written.
*
* @param string[] $changes Always passed empty; a callback returns the field or meta keys it changed.
* @param WP_REST_Request $request The REST request object.
* @param array<string, mixed> $entry The entry as it was before the update, keyed by field ID alongside the entry properties.
* @param FeedRow $feed The feed.
*
* @return string[]|WP_Error[]|WP_Error The extra changed keys, or a WP_Error to fail the whole update.
*/
$additional_changes = apply_filters( 'gk/gravityboard/card/update-card', [], $request, $entry, $feed );gk/gravityboard/data/lanes
/**
* Filter lanes data before returning.
*
* @since 1.0
*
* @param array<int, array{id: string, title: string, value: string, color: string, cards: array<int, array<string, mixed>>, catch_all?: bool, disallowAddingCard?: bool}> $lanes The lanes keyed by lane ID, before array_values() flattens them into the response.
* @param array<int, array<string, mixed>> $entries The entries the lanes were built from, keyed by field ID alongside the entry properties.
* @param FeedRow $feed The feed.
*/
$lanes = apply_filters( 'gk/gravityboard/data/lanes', $lanes, $entries, $feed );gk/gravityboard/lane/sorted-cards
/**
* Filter the sorted cards within a lane.
*
* @since 1.4.0
*
* @param array $cards The sorted cards.
* @param array $lane The lane data.
* @param array $feed The feed data.
*
* @return array
*/
$lane['cards'] = apply_filters( 'gk/gravityboard/lane/sorted-cards', $lane['cards'], $lane, $feed );gk/gravityboard/card/comparison-value
/**
* Filter the form of a field value used to decide whether a card save changed it.
*
* Return a key that is equal for two values meaning the same thing, so a save that
* only reformats a value is not reported, notified or written as a change.
*
* @since 1.5.0
*
* @param mixed $value The stored or submitted value.
* @param \GF_Field|false $field The Gravity Forms field, or false when the form no longer has it.
* @param FeedRow $feed The feed data.
*/
return apply_filters( 'gk/gravityboard/card/comparison-value', $value, $field, $this->feed );gk/gravityboard/card/self-managed-keys
/**
* Filter the card keys an integration fills in itself.
*
* A key listed here is left out of the card's stored field values and its
* `choice_field_values`, so only the integration's own card data sets it.
*
* @since 1.5.0
*
* @param string[] $keys Card field keys.
* @param FeedRow|array{} $feed The feed data.
*/
$keys = apply_filters( 'gk/gravityboard/card/self-managed-keys', [], $feed );gk/gravityboard/card/writable-fields
/**
* Filter the mapped card fields a create or update may write.
*
* Removing a key here leaves the mapping in place but stops the card API
* reading that key from the request, so a value the editor never showed
* cannot be overwritten by one it never held.
*
* @since 1.5.0
*
* @param array<string, string> $mapped_fields Card field key => mapped field ID.
* @param FeedRow $feed The feed data.
*/
$writable = apply_filters( 'gk/gravityboard/card/writable-fields', $mapped_fields, $this->feed );gk/gravityboard/card/lock_timeout
/**
* Filters how many seconds a card waits for another card joining a lane of the same form.
*
* @param int $seconds Seconds to wait. Default 5.
* @param int $form_id The form id.
*/
$wait = $wait ?? (int) apply_filters( 'gk/gravityboard/card/lock_timeout', 5, $form_id );The wait applies when a card is added or moved, and when a card save moves it to another lane. When it runs out, the request fails with card_busy (HTTP 409), listed under Error responses below.
gk/gravityboard/lane/lock_timeout
/**
* Filters how many seconds a lane change waits for another lane change on the same form.
*
* @param int $seconds Seconds to wait. Default 5.
* @param int $form_id The form id.
*/
$wait = (int) apply_filters( 'gk/gravityboard/lane/lock_timeout', 5, $form_id );The wait applies when a lane is added, edited, moved, or deleted. When it runs out, the request fails with lane_busy (HTTP 409).
gk/gravityboard/data/max-entries
/**
* Filters the most entries a board renders.
*
* A value below one is discarded, since a board that renders nothing is never
* what a site meant to ask for.
*
* @since 1.5.0
*
* @param int $max_entries What the host can afford. See Feed::default_max_entries_per_board().
* @param FeedRow|array{} $feed The feed the board is built from.
*/
$max_entries = (int) apply_filters( 'gk/gravityboard/data/max-entries', $default, $feed );gk/gravityboard/data/pagination
/**
* Filter pagination data before returning.
*
* @since 1.5.0
*
* @param array{total: int, per_page: int, offset: int, count: int, has_more: bool} $pagination The pagination data.
* @param FeedRow $feed The feed.
* @param array{offset: int, page_size: int} $paging The paging arguments the entry query ran with.
* @param int $total_entries The total number of entries matching the query.
*/
$pagination = apply_filters( 'gk/gravityboard/data/pagination', $pagination, $feed, $paging, $total_entries );Board and rendering filters
gk/gravityboard/board-settings
/**
* Filter the board settings before they are passed to the frontend React application.
*
* @since 1.0
*
* @param array $board_settings The board settings.
* @param int $feed_id The ID of the feed.
*
* @return array The board settings.
*/
$board_settings = apply_filters( 'gk/gravityboard/board-settings', $board_settings, $feed_id );gk/gravityboard/translation-overrides
/**
* Filters the translation overrides for the GravityBoard.
*
* @since 1.0
*
* @param array<string, string[]> $translation_overrides The translation overrides.
* @param int $feed_id The ID of the feed.
*
* @return array<string, string[]> Locale data for wp.i18n.setLocaleData(): original string => the strings to replace it with.
*/
$translation_overrides = apply_filters( 'gk/gravityboard/translation-overrides', [], $feed_id );gk/gravityboard/renderer/css-variable-overrides
/**
* Filters the CSS variable overrides for the GravityBoard.
*
* @since 1.0
*
* @param array $css_overrides The CSS overrides, with the key as the full CSS variable name and the value as the CSS value.
* @param array $feed The feed.
*
* @return array
*/
$css_overrides = apply_filters( 'gk/gravityboard/renderer/css-variable-overrides', $css_overrides, $feed );gk/gravityboard/feed/field-config
/**
* Filter the editor configuration of a mapped form field.
*
* @since 1.5.0
*
* @param array<string, mixed> $field_config `type`, plus `choices`, `required`, `read_only`, `placeholder` and `maxLength` where they apply.
* @param \GF_Field $field The Gravity Forms field.
* @param FeedRow $feed The feed data.
*/
$filtered_config = apply_filters( 'gk/gravityboard/feed/field-config', $field_config, $field, $feed );gk/gravityboard/renderer/skip-offscreen-cards
/**
* Filters whether the board leaves off-screen cards unrendered.
*
* @since 1.5.0
*
* @param bool $skip Whether to skip them. Default true.
* @param FeedRow|array{} $feed The feed the board is built from.
*/
return (bool) apply_filters( 'gk/gravityboard/renderer/skip-offscreen-cards', true, $feed );Return false to draw every card when the board loads. Safari’s find-in-page does not match text in a card that has not been drawn yet.
gk/gravityboard/views/available
/**
* Filter the available views for the board.
*
* @since 1.5.0
*
* @param string[] $available_views The available views.
* @param FeedRow $feed The feed data.
*/
$available_views = apply_filters(
'gk/gravityboard/views/available',
$this->get_available_views( $feed ),
$feed
);gk/gravityboard/views/default
/**
* Filter the default view for the board.
*
* @since 1.5.0
*
* @param string $default_view The default view.
* @param FeedRow $feed The feed data.
* @param string[] $available_views The available views.
*/
$default_view = apply_filters(
'gk/gravityboard/views/default',
$this->get_default_view( $available_views ),
$feed,
$available_views
);Permissions filters
gk/gravityboard/permissions/admin-has-full-access
/**
* Filters whether an admin user bypasses all board permission checks.
*
* @since 1.4.0
*
* @param bool $has_full_access Whether the user has full access. Default: true for admins.
* @param int $user_id The user ID being checked.
*
* @return bool
*/
$has_full_access = (bool) apply_filters( 'gk/gravityboard/permissions/admin-has-full-access', $has_full_access, $user_id );See Admin bypass for GravityBoard permissions for usage examples and context.
Feature-specific filters
gk/gravityboard/notes/filter-by-board
/**
* Filter whether to filter notes by board so only notes created on the current board are returned.
*
* @since 1.0
*
* @param bool $filter_notes_by_board Whether to filter notes by board.
* @param int $feed_id The feed ID.
*
* @return bool
*/
$filter_notes_by_board = apply_filters( 'gk/gravityboard/notes/filter-by-board', false, $feed_id );gk/gravityboard/notes/allowed-html
/**
* Filter the HTML a card note may contain. Add `img` back to allow images in notes.
*
* @since 1.5.0
*
* @param array<string, array<string, bool>> $allowed The allowed HTML, in the shape wp_kses() takes: tag name => attribute name => allowed.
*/
$allowed = apply_filters( 'gk/gravityboard/notes/allowed-html', $allowed );gk/gravityboard/attachments/blocked-extensions
/**
* Filters the file extensions refused on a board that allows every file type.
*
* Every extension in a file name is checked, so `report.php.jpg` is refused for `php`.
* Remove an extension from the list only when the site serves that type safely.
*
* @param string[] $extensions Lowercase extensions, without the dot.
*/
$extensions = (array) apply_filters( 'gk/gravityboard/attachments/blocked-extensions', self::BLOCKED_EXTENSIONS );The list applies only on a board with Allow All File Types on; otherwise WordPress decides which file types are allowed. The default list holds 66 extensions, among them php, phar, html, svg, js, and exe.
gk/gravityboard/checklists/export-value
/**
* Filters the export text for checklists in CSV or other export formats.
*
* @since 1.1
*
* @param string $export_text The export text, which is a string of checklist items and their statuses.
* @param ChecklistCollection $checklists The checklists collection.
*
* @return string The filtered export text.
*/
$export_text = apply_filters( 'gk/gravityboard/checklists/export-value', $export_text, $checklists );gk/gravityboard/voting/can-spend-vote
/**
* Filters whether a user can spend a vote.
*
* Return true to allow or a WP_Error to deny with a message.
*
* @since 1.4.0
*
* @param true|WP_Error $allowed Whether the vote is allowed.
* @param int $feed_id The feed ID.
* @param int $user_id The user ID.
* @param int $entry_id The entry (card) ID.
* @param array $budget Budget info from get_budget().
*
* @return bool|WP_Error
*/
$allowed = apply_filters( 'gk/gravityboard/voting/can-spend-vote', true, $feed_id, $user_id, $entry_id, $budget );gk/gravityboard/voting/budget-total
/**
* Filters the total vote budget for a user.
*
* Allows role-based budgets, dynamic budgets, etc.
*
* @since 1.4.0
*
* @param int $total The total budget (0 = unlimited).
* @param int $feed_id The feed ID.
* @param int $user_id The user ID.
*
* @return int
*/
return (int) apply_filters( 'gk/gravityboard/voting/budget-total', $total, $feed_id, $user_id );gk/gravityboard/merge-tags/assignee-user-id
/**
* Filter the assignee user.
*
* @internal Do not rely on this filter; it is designed for internal use only.
* @used-by Assignees::handle_assignee_change()
*
* @since 1.0
*
* @param int|null $assignee_user_id The assignee user ID.
* @param array<string, mixed> $entry The Gravity Forms entry.
*/
$assignee_user_id = apply_filters( 'gk/gravityboard/merge-tags/assignee-user-id', $notification_user_id, $entry );gk/gravityboard/merge-tags/assignee-properties
/**
* Filters the user fields `{gravityboard_assignee:<property>}` may read.
*
* Anything not listed renders empty. Add a user meta key only when its value is safe to
* put in an email. A property on Foundation's `gk/foundation/merge-tags/preview/denylist`,
* or a private meta key, renders empty even when listed.
*
* @param string[] $properties Property names as WP_User::get() takes them.
*/
$properties = (array) apply_filters( 'gk/gravityboard/merge-tags/assignee-properties', $properties );The default list is ID, id, user_login, user_nicename, user_email, user_url, display_name, nickname, first_name, last_name, and description. See Merge tags added by GravityBoard.
Deprecated methods #
Each method still works and triggers a deprecation notice when debugging is on. Ajax::can_add_attachment() and Ajax::can_delete_attachment() now answer with the board’s attachment permissions, where they used to answer with the card edit permission. The two constants still hold the same colors. Use the replacements instead.
| Deprecated | Replacement |
|---|---|
Ajax::can_add_attachment( WP_REST_Request $request ) | Attachments::can_upload_attachment( $request ), which the old method now calls and returns |
Ajax::can_delete_attachment( WP_REST_Request $request ) | Attachments::can_delete_attachment( $request ), which the old method now calls and returns |
Helpers::has_entries_in_lane( int $form_id, int $lane_field_id, string $lane_value ) | Helpers::get_lane_entry_ids( int $form_id, int $lane_field_id, array $lanes, string $lane_id, string $status = 'active' ), which takes the board’s lanes and a lane ID and returns the entry IDs in that lane (test the result for emptiness) or a WP_Error |
Feed::DEFAULT_DARK_TEXT_COLOR | GravityKit\GravityBoard\Integrations\EntryTags::DEFAULT_DARK_TEXT_COLOR (#101517) |
Feed::DEFAULT_LIGHT_TEXT_COLOR | GravityKit\GravityBoard\Integrations\EntryTags::DEFAULT_LIGHT_TEXT_COLOR (#fff) |
Abilities #
GravityBoard 1.6.0 and later registers board, lane, and card abilities with the WordPress Abilities API, which needs WordPress 6.9 or later. The GravityKit MCP turns them into its gb_ tools. Setup and examples are in Building boards with AI using the GravityKit MCP.
Each ability runs at /wp-json/wp-abilities/v1/abilities/gk-gravityboard/<name>/run. The read-only abilities take a GET request, board-delete and card-delete take a DELETE, and the rest take a POST.
| Ability | What it does |
|---|---|
gk-gravityboard/boards-list | Lists the boards on the site |
gk-gravityboard/board-get | Returns one board and its settings |
gk-gravityboard/board-settings-schema | Lists the settings a board accepts and the form fields each one can use |
gk-gravityboard/board-create | Creates a board on a form |
gk-gravityboard/board-update | Changes a board’s settings |
gk-gravityboard/board-delete | Deletes a board |
gk-gravityboard/lane-create | Adds a lane |
gk-gravityboard/lane-update | Renames a lane |
gk-gravityboard/lane-move | Moves a lane |
gk-gravityboard/lane-delete | Deletes a lane |
gk-gravityboard/cards-list | Lists a board’s cards |
gk-gravityboard/card-create | Adds a card |
gk-gravityboard/card-update | Edits a card |
gk-gravityboard/card-move | Moves a card to another lane or position |
gk-gravityboard/card-delete | Deletes a card |
The board abilities need the Gravity Forms Edit Forms capability. The lane and card abilities check the board’s own permission settings, the same ones the board page uses, so an account can do through an ability only what it could do on the board.
REST API #
The board reads and saves its data through REST routes under https://your-site.com/wp-json/gravityboard/v1/boards/{feed_id}/, where {feed_id} is the board’s ID. The tables below list the routes for cards, lanes, notes, attachments, checklists, and votes.
Since GravityBoard 1.6.0, board users and card assignees in the board data no longer include email. A note’s user_email is empty unless the current user has the Gravity Forms Edit Forms capability.
Cards (entries)
| Method | Endpoint | Description | Payload fields (JSON) |
|---|---|---|---|
GET | /gravityboard/v1/boards/{feed_id}/cards | Retrieve the board’s lanes with their cards, up to the board’s entry limit (gk/gravityboard/data/max-entries). pagination.has_more in the response is true when more entries match. | N/A |
POST | /gravityboard/v1/boards/{feed_id}/cards | Create a new card on the specified board. | One parameter per card field:
|
PATCH | /gravityboard/v1/boards/{feed_id}/cards/{entry_id} | Update an existing card. | One parameter per card field to change:
|
PUT | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/move | Move a card to another lane, or reorder it within the same lane. |
|
DELETE | /gravityboard/v1/boards/{feed_id}/cards/{entry_id} | Delete a card. | N/A |
Lanes
A lane’s ID is the position of its choice in the lane field, counting from 0. Moving or deleting a lane changes the IDs of the lanes after it, so read the IDs again after either.
| Method | Endpoint | Description | Payload fields (JSON) |
|---|---|---|---|
POST | /gravityboard/v1/boards/{feed_id}/lanes | Create a new lane for the specified board. | title (string): The name of the new lane. |
PATCH | /gravityboard/v1/boards/{feed_id}/lanes/{lane_id} | Rename a lane. | title (string): The new name for the lane. |
PUT | /gravityboard/v1/boards/{feed_id}/lanes/{lane_id}/move | Move a lane to a new position. | position (integer, required): The lane’s new zero-based index. |
DELETE | /gravityboard/v1/boards/{feed_id}/lanes/{lane_id} | Delete a lane. | N/A |
Notes
| Method | Endpoint | Description | Payload fields (JSON) |
|---|---|---|---|
GET | /gravityboard/v1/boards/{feed_id}/notes | Retrieve all notes for a specific card (entry). | entry_id (integer, required): The card’s entry ID, as a query parameter. |
POST | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/notes | Add a new note to a specific card. | note (string): The content of the note. |
PUT | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/notes/{note_id} | Update an existing note on a card. | note_content (string): The updated content of the note. |
DELETE | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/notes/{note_id} | Delete a note from a card. | N/A |
Attachments
| Method | Endpoint | Description | Payload fields (form data) |
|---|---|---|---|
POST | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/attachments | Add a new attachment to a specific card. | file (file): The file to be uploaded. |
DELETE | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/attachments/{attachment_id} | Delete an attachment from a card. | N/A |
Checklists
| Method | Endpoint | Description | Payload fields (JSON) |
|---|---|---|---|
GET | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/checklists | Retrieve all checklists for a specific card. | N/A |
PUT | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/checklists | Update entire checklists for a card. | checklists (array): Array of checklist objects. |
POST | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/checklists/{checklist_id}/items | Add a new checklist item to a card. | label (string): The item label. |
PUT | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/checklists/{checklist_id}/items/{item_id} | Update an existing checklist item. |
|
DELETE | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/checklists/{checklist_id}/items/{item_id} | Delete a checklist item from a card. | N/A |
Votes
| Method | Endpoint | Description | Payload fields (JSON) |
|---|---|---|---|
POST | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/vote | Add the current user’s vote to a card, or take one back. | vote (integer, required): 1 or -1, added to the user’s vote weight on the card. |
GET | /gravityboard/v1/boards/{feed_id}/cards/{entry_id}/voters | List the users who voted on a card. | N/A |
Authentication
Requests run as the WordPress user they sign in as, through any authentication the WordPress REST API accepts, such as the logged-in cookie with a wp_rest nonce or an application password.
Permissions
The API is protected by the permissions associated with the feed; that is why the feed ID is required in the URL. See Admin bypass for GravityBoard permissions for details on how administrator access interacts with these checks.
Error responses
A refused request answers with a WordPress REST error object: a code, a message, and an HTTP status.
| Status | Code | When |
|---|---|---|
| 404 | feed_not_found | The board ID in the URL does not resolve to an active board. The response is the same whether or not a board with that ID exists. |
| 404 | entry_not_found | The entry ID does not exist, belongs to a form other than the board’s, or is a card the board’s Conditional Logic hides from the current user. The response does not distinguish these cases. |
| 404 | entry_not_active | The card is in the Gravity Forms trash or marked as spam. |
| 401 | gk_gravityboard_login_required | A visitor who is not logged in tries to vote. |
| 403 | rest_forbidden | The board’s permissions do not grant the action to the current user, on the card, lane, and note routes. A visitor who is not logged in receives 401 instead. |
| 403 | gk_gravityboard_permission_denied | The board’s permissions do not grant the action, on the attachment, checklist, and vote routes. |
| 403 | gk_gravityboard_notes_disabled | Enable Entry Notes is off for the board. |
| 403 | gk_gravityboard_attachments_disabled | Enable Card Attachments is off for the board. |
| 403 | gk_gravityboard_checklists_disabled | Enable Card Checklists is off for the board. |
| 403 | gk_gravityboard_voting_disabled | Enable Voting is off for the board. |
| 409 | card_busy | Another card change on the same form held its lock longer than gk/gravityboard/card/lock_timeout allows (5 seconds by default). On a PATCH, the error data lists the fields already saved under persisted_changes. |
| 409 | lane_busy | Another lane change on the same form held its lock longer than gk/gravityboard/lane/lock_timeout allows (5 seconds by default). |
| 409 | gk_gravityboard_vote_busy | The voter’s previous vote is still being saved. |
| 413 | gk_gravityboard_file_too_large | The uploaded file is larger than the server accepts. |
| 400 | validation_failed | A card field’s value fails its Gravity Forms field’s validation when a card is added or saved. The error data lists each field under errors, with its field_name and message. |
| 400 | field_not_editable | A card add or save names a card field the board can’t write: one mapped to a field such as File Upload, List, Signature, or a product field, or a Card Description set to Custom text (with merge tags). The error data names the field under field_name. |
| 400 | conflicting_lanes | A card save names two different lanes. |
| 400 | invalid_json, invalid_card_ids, too_many_card_ids | The ordered_card_ids of a move is not valid JSON, holds something other than card IDs, or lists more cards than the board can show. |
| 400 | lane_field_not_choice | The board’s lane field has no choices, so the board has no lanes. |
| 400 | gk_gravityboard_file_type_not_permitted | The uploaded file’s type is refused. On a board with Allow All File Types on, the list is gk/gravityboard/attachments/blocked-extensions. |