AfterShip Post-Purchase
Manage shipments and returns
- Category
- Pending
- Primary Subcategory
- Pending
Integration details
Description
AfterShip Post-Purchase for ChatGPT makes shipment and returns operations as easy as having a conversation. Connect your AfterShip data and simply chat to search shipments, review delivery status and tracking timelines, spot exceptions, look up specific orders, or review return and RMA details including refund progress, shipping status, returned items, and outcomes. Then act on what you find: with your confirmation, ChatGPT can correct shipment records, re-track stalled shipment, mark a final delivery status, and move returns through approval, receiving, and resolution — always scoped to your organization and your own AfterShip role.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Category
- Pending
- Primary Subcategory
- Pending
- Secondary Subcategories
- None listed
- Brand
- Unknown
- Access
- Account required
- First tracked
- 2026-09-24
- Tool count
- 22
- Geography
- US
The broad Category that contains the Primary Subcategory.
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
Get alerts for AfterShip Post-Purchase
Get updates when AfterShip Post-Purchase’s Discoverability Score or category rank changes.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competitive lineup
22 tools agents can invoke
Create one or more return allowlist rules for the authorized org. This is a BATCH call: every element of `allow_rules` becomes a new rule in a single request. BUSINESS RISK — read before every call: an allowlist rule lets matching returns through the merchant's normal return policy. Nothing errors out; the return simply goes through. A broad condition (an entire product_type, product_tag or order_tag, or a discount threshold, rather than one specific order, item or customer) can waive the policy for a large share of orders and create real refund cost. Whenever a rule is broad, spell out its blast radius to the user before creating it. Before calling, show the user the exact rules you are about to create — for each one the `condition`, the `operator` and every entry of `values` — and get their explicit confirmation. Do not invent conditions or values the user did not state. RULE SHAPE — each element is exactly {condition, operator, values[]}. `values` is always an ARRAY, and its length is fixed by `operator`: exactly 1 for is_value / equal_greater_than_value / equal_less_than_value, exactly 2 for between_values (lower bound first). A wrong count is rejected before the call is made. Do NOT send the shape returned by list_return_allowlist (which nests {key, operator, value} under `conditions`) — that is the read shape and the upstream rejects it. MATCHING SEVERAL VALUES — there is no multi-value / "in" / "any of" operator. To allow, say, four product types, send FOUR rules in the same call, each `is_value` with one value. Do not pack several values into one rule and do not invent an operator name; only the four listed operators exist and anything else is rejected before the call is made. The allow-rule `condition` list is NOT the block-rule one: this tool accepts `order_name`, while `order_tag` belongs to add_return_blocklist and is rejected here. That single value is the only difference between the two lists. Use the value list documented on the field; never copy condition values between the two tools. This tool is NOT idempotent — calling it twice creates duplicate rules. If a call appears to have failed, call list_return_allowlist to check whether the rules were already created before you retry.
add_return_allowlist
Create one or more return BLOCKLIST rules for the authorized org. This is a BATCH call: every element of `block_rules` becomes a new rule in a single request, and the call is NOT idempotent — calling it twice creates duplicate rules. If a call appears to have failed, run list_return_blocklist to check whether the rules already exist before retrying. BUSINESS RISK — read before every call: a blocklist rule silently blocks real customers from starting a return. Nothing errors out; the shopper simply cannot file an RMA. A broad condition (an entire product_type, product_tag or order_tag, rather than one specific order, item or customer) can block a large share of legitimate returns. Whenever a rule is broad, spell out its blast radius to the user before creating it. Before calling, show the user a summary of every rule you are about to create — its `condition`, its `operator` and every entry of `values` — and get their explicit confirmation. Never invent a condition or a value the user did not state. RULE SHAPE — each element is exactly {condition, operator, values[]}. `values` is always an ARRAY, and its length is fixed by `operator`: exactly 1 for is_value / equal_greater_than_value / equal_less_than_value, exactly 2 for between_values (lower bound first). A wrong count is rejected before the call is made. Do NOT send the shape returned by list_return_blocklist (which nests {key, operator, value} under `conditions`) — that is the read shape and the upstream rejects it. MATCHING SEVERAL VALUES — there is no multi-value / "in" / "any of" operator. To block, say, four product types, send FOUR rules in the same call, each `is_value` with one value. Do not pack several values into one rule and do not invent an operator name; only the four listed operators exist and anything else is rejected before the call is made. The blocklist condition values are NOT the same as the allowlist ones: the blocklist takes `order_tag` where the allowlist takes `order_name`. That single value is the only difference between the two lists. Use the value list documented on each field; never copy condition values between the two tools.
add_return_blocklist
Post an INTERNAL note on the timeline of one RMA. It is written for the merchant team and is never sent to the shopper. Before calling, show the user the exact comment text you are about to post and the target `rma_number`, and get their explicit confirmation. Do not rewrite, expand, summarise or invent wording the user did not state. The `rma_number` comes from list_returns or get_return — never guess it, never construct it, and never pass an order number in its place. `content` is PLAIN TEXT. Rich text / markdown, @mentions and attachments are not supported in this release; do not attempt them. The server stores the text wrapped in <p>…</p> and echoes it back that way — show it as-is, do not strip the tags and do not escape it again. This tool is NOT idempotent: calling it twice leaves two comments, and there is no tool to edit or delete a comment once posted. If you are unsure whether a previous call succeeded, ask the user — do not retry on your own.
add_return_comment
Approve ONE submitted return (RMA), moving it to the `approved` state. Requires an `rma_number` obtained from list_returns or get_return — never guess or construct one. Precondition: the RMA must currently be `submitted` (Pending approval). The RMA lifecycle cannot skip steps: submitted → approved → received → resolved, or submitted → rejected. Call get_return first to verify the current state instead of assuming it; approving an RMA that is not `submitted` is refused upstream. This is a write that this server cannot undo — there is no un-approve tool. Show the user a summary (which RMA, its current state, the state it will move to, and who it affects) and get their explicit confirmation before calling. Approval only opens the return; it does NOT receive items, resolve the return, or move any money. Never tell the user or the shopper that a refund or an exchange has been completed. Returns `{ rma_number, rma_status, note }`. `note` is null on a normal success; when the upstream does not echo the new state, `rma_status` is null and `note` says the action was executed and to read the current state via get_return instead of retrying. Render `rma_status` as its label, never the raw code: `submitted`→Pending approval, `approved`→Approved, `done`→Resolved, `rejected`→Rejected, `expired`→Expired.
approve_return
Return the available values (with display labels) for ONE filter dimension. Two kinds of field, do not confuse them: **org-derived** fields return only the values this org actually has, each with a `count`; **dictionary** fields return AfterShip's global catalogue — stable values + labels, NO count, and NOT an indication of what this org uses. Call this FIRST (facets-first), before a list tool, so you filter with valid values and avoid empty results — and so you can show the human label instead of the raw code. One `field` per call, and every field name carries its own product prefix — `tracking.` for shipment dimensions, `returns.` for RMA dimensions — so the prefix is all that selects the source. The full option set is returned in a single call — there is no pagination, so you can pick from the complete list (tracking fields are capped at the upstream maximum of 1500 values; if the response carries `truncated: true`, narrow with `q`). Only pass `q` when the list is large and you already know roughly what to look for; it is a case-insensitive substring match over value and label. `tracking.status`, `tracking.sub_status` and `tracking.carrier_slug` are the dictionary fields (no `count`); every other field is org-derived (has `count`). In particular `tracking.carrier_slug` lists ~1500 carriers AfterShip supports, most of which this org has never shipped with — never present it as "the carriers you use", and never pick from it to answer "which carriers does my org have". To answer that, call the list tool and aggregate by carrier instead. Name mismatch to watch: the prefix belongs to THIS tool only — the list tools take the bare name, and sometimes a different one: values from `field=tracking.status` go into the list_shipments parameter named `latest_status`. Discovery-only fields (not accepted as list_shipments filter inputs): `tracking.sub_status`, `tracking.order_tags`, `tracking.store_slug`, `tracking.custom_field_keys`. Read-only.
get_field_options
Return the curated full detail of ONE RMA by its `rma_number` (from list_returns): identity, approval/shipping/refund status, outcome, order, return_items, exchange, receivings, restocks, shipments, amounts (cost_of_return / estimated_refund_total / refunded_total), and key timestamps incl. updated_at. Use list_returns FIRST to obtain a valid rma_number (List→Detail); do not guess RMA numbers. Status fields are enum-coded — render their labels (per the list_returns filter map) when showing them. A foreign/unknown rma_number fails closed as return_not_found. Read-only. Output enum display labels (render the label, never the raw code): - rma_status / shipping_status / refund_status / outcome / return_method / grade / exception: reuse the same value→label maps from the matching list_returns filter. - approval_status: `submitted`→Pending approval, `approved`→Approved, `rejected`→Rejected, `expired`→Expired, `done`→Resolved. - refund_destination: `original_payment`→Refund to original payment method, `store_credit`→Refund to store credit. - refund_methods: render the value directly (no mapping).
get_return
Return the full definition of ONE return workflow by its `id`. This is the only place where the trigger `conditions` are visible — the list view deliberately omits them — so use this whenever the user asks WHEN or WHY a workflow fires, on top of id, name, priority, status, applied_status, action_type, errors, action and timestamps. The `id` must come from list_return_workflow (List→Detail). Do not guess it, do not construct it, and do not pass a workflow name — resolve the id first. An id that belongs to another organization fails closed and is reported as `return_workflow_not_found`, exactly like an id that does not exist; do not read anything into the distinction and do not retry with variations of the id. Read-only: this tool inspects configuration and never changes anything.
get_return_workflow
Return the curated full detail of ONE shipment by its `id` (the `tracking_id` from list_shipments). Fields follow the upstream Tracking API names: status / substatus / substatus_message, return_to_sender / damaged / lost, order_date / shipment_pickup_date / shipment_delivery_date, flat origin_* and destination_* address fields, service_type {name, code, standardized_name}, latest_estimated_delivery_date / order_promised_delivery_date objects, on_time_status, customers (when permitted), and the full `checkpoints` timeline (each with status / substatus / checkpoint_time / city / state / country_region / checkpoint_hash). `id` is NOT a tracking number, last-mile number, order number/id, shipment title, customer name/email/phone, SKU, or any note/custom-field value. If the user supplies any of those, call list_shipments FIRST to resolve the `tracking_id`, then call this tool; if list_shipments returns multiple candidates, ask the user to choose (do not guess). A foreign/unknown id fails closed as tracking_not_found. Read-only. Output enum display labels (render the label, never the raw code): - status / checkpoints[].status: `Pending`→Pending, `InfoReceived`→Information Received, `InTransit`→In Transit, `OutForDelivery`→Out for Delivery, `AvailableForPickup`→Available for Pickup, `Delivered`→Delivered, `AttemptFail`→Failed Attempt, `Exception`→Exception, `Expired`→Expired. - on_time_status: `on-time`→On time, `early`→Early, `late`→Late, `overdue`→Overdue, `trending-on-time`→Trending-On-Time, `trending-late`→Trending late, `trending-early`→Trending early. - substatus / checkpoints[].substatus: resolve value→label via get_field_options(field=tracking.sub_status). When displaying results, resolve human labels for the get_field_options-sourced coded fields (carrier_slug, service_type, shipping_method, origin/destination country_region/state/city, sub_status) by calling get_field_options(field=tracking.…), and show the label, not the raw code.
get_shipment
List the return allowlist rules configured for the authorized org (Returns settings → allowlist). Each rule is flat: a `condition` type (what is matched), an `operator` (how it is matched) and `values` (an array — one element for single-value operators, two for `between_values`). Always quote the `operator` and `values` back to the user when describing a rule; the `condition` alone does not tell them what the rule actually matches. Filter by `q` — an EXACT match on one complete rule value, where a prefix or substring matches nothing and an empty result does not prove the rule is absent — and/or by a `condition` type. Paginated: `page` is 1-based (upstream default 1, declared maximum 10) and `limit` is the page size (upstream default 60, declared maximum 200). The response reports `has_next_page` but the upstream returns NO total count — never state, estimate, or compute how many allowlist rules exist in total; if `has_next_page` is true, say that more pages are available and offer to fetch the next page. Each rule's `id` is the identifier that remove_return_allowlist requires: always take it from this tool's output, never construct or guess it (List→Write). Read-only.
list_return_allowlist
List the return BLOCKLIST rules configured for the authorized org (Returns settings → blocklist). A blocklist rule PREVENTS the matching orders / items / customers from starting a return. This is a separate list from the return allowlist, and the two do NOT share the same condition values — the blocklist takes `order_tag` where the allowlist takes `order_name`. Never copy condition values between the two tools. Each rule is flat: a `condition` type (what is matched), an `operator` (how it is matched) and `values` (an array — one element for single-value operators, two for `between_values`). Always quote the `operator` and `values` back to the user when describing a rule; the `condition` alone does not tell them what the rule actually matches, and remove_return_blocklist needs the user to be able to tell two same-condition rules apart. Filter by `q` — an EXACT match on one complete rule value, where a prefix or substring matches nothing and an empty result does not prove the rule is absent — and/or by a `condition` type. Paginated: `page` is 1-based (upstream default 1, declared maximum 10) and `limit` is the page size (upstream default 60, declared maximum 200). The response reports `has_next_page` but the upstream returns NO total count — never state, estimate, or compute how many blocklist rules exist in total; if `has_next_page` is true, say that more pages are available and offer to fetch the next page. Each rule's `id` is the identifier that remove_return_blocklist requires, and this tool is its only source: always take the id verbatim from this output, never construct or guess it (List→Write). Read-only.
list_return_blocklist
List the return workflows (the configurable rules that shape how returns are handled) for the authorized org. This endpoint returns all of them in one call: there is no pagination — no page or limit input, no next page, no total count. Do not try to page through the result. Two optional filters: `action_type` (which kind of action the workflow performs, 12 documented values) and `status` (`active` = live, `draft` = saved but not published). Omit both to see everything. Each row carries id, name, priority, status, applied_status, action_type, errors, action, created_at and updated_at. The trigger `conditions` are deliberately NOT included here — take the `id` of the row you care about and call get_return_workflow to see them. Read-only: this tool inspects configuration and never changes anything.
list_return_workflow
Search returns (RMAs) of the authorized org with a free-text `q` plus named {operator, values} filters, and return a paginated list of RMA objects: identity, status enums, key dates, amounts, and array counts. Returns enums are STATIC and inlined per filter: read the allowed values off the filter description itself, do not go looking for them elsewhere. Two exceptions are merchant-defined and vary per organization, so their values MUST come from get_field_options(field=returns.reason_with_subreason) and get_field_options(field=returns.merchant_tag_ids) — the filters here carry the same names with the prefix dropped. When you show an enum to the user, render its label (see each filter below), not the raw code. When the user filters by an enum, map their wording to the machine value. No default created-time window is injected; pass return_created_at {operator:"is_between", values:[from,to]} to scope by creation time. Page size default 10, max 50. Then call get_return with an rma_number for full detail (List→Detail). Present results as a complete table. Read-only.
list_returns
Search shipments of the authorized org and return a paginated list. Each row carries the upstream summary fields — tracking_id, tracking_number, carrier_slug, store_slug, order_id, shipment_title, source, status, return_to_sender / damaged / lost, on_time_status, transit_time, created_at, shipment_tags, origin_*/destination_* (country_region, state, city, postal_code, raw_location), service_type {name, code, standardized_name}, latest_estimated_delivery_date {estimated_delivery_date, …}, and a one-element `checkpoints` summary — plus an `admin_url`. Pass `tracking_id` as `id` to get_shipment for the full detail (List→Detail). The summary has no substatus / order_number / store_name; call get_shipment when those are needed. The single checkpoint in a row is not guaranteed to be the latest event. Use this for "find / filter / group / summarize shipments" questions. For value-bearing filters (carrier_slug, service_type, shipping_method, origin/destination country_region/state/city) call get_field_options(field=tracking.…) FIRST and use the exact values it returns; do not feed back display values from a prior result. No default time window is applied — pass a date range to scope by date; omit it for locator queries (by tracking/order/customer). Page size default 10, max 50; paginate with `page`. Present results as a complete table (all fields, no omission). When displaying results, resolve human labels for the get_field_options-sourced coded fields (carrier_slug, service_type, shipping_method, origin/destination country_region/state/city, sub_status) by calling get_field_options(field=tracking.…), and show the label, not the raw code. Read-only.
list_shipments
DEPRECATED — use `get_field_options` instead, which covers the same tracking dimensions plus other products and returns the full option set in one call. This tool is kept only for backward compatibility and will be removed; do not choose it when `get_field_options` is available. Return the authorized org's available values (with display labels) for ONE tracking filter dimension. Pass a single `field` per call. For normal use, call WITHOUT `q` first (returns up to `limit` rows, default 100); only if that first query does not surface the option you need, add `q` — a case-insensitive fuzzy search over both value and label — to find it. carrier_slug and sub_status are normalized dictionaries (stable values + labels, no counts); the other fields are derived from the org's data and include a count. Note: order_tags and store_slug are discovery-only (not yet accepted as list_shipments filter inputs); service_type IS a valid list_shipments filter input; sub_status is for resolving display labels (not a list_shipments input). Read-only.
list_tracking_filter_options
Manually mark ONE shipment as reaching a final state: `delivered`, `lost`, or `returned_to_sender`. Requires the shipment `id` (the `tracking_id` from list_shipments) — never a tracking number. This overrides what the carrier reports and is hard to walk back, so state the shipment and the exact reason to the user and get their confirmation before calling. Never infer the reason from context — if the user has not said which of the three applies, ask. `event_datetime` accepts `YYYY-MM-DD`, `YYYY-MM-DDTHH:mm:ss` or `YYYY-MM-DDTHH:mm:ss±hh:mm` (no `Z` suffix, no fractional seconds); omit it to let the upstream default it. Returns the shipment detail after marking.
mark_shipment_status
Record that returned items physically arrived for ONE RMA, optionally with quality-inspection grades. Requires an `rma_number` obtained from list_returns or get_return — never guess one. Precondition: the RMA must currently be `approved`. The RMA lifecycle cannot skip steps: submitted → approved → received → resolved, or submitted → rejected. Call get_return first to verify the current state instead of assuming it. Every `items[].external_order_item_id` MUST be copied verbatim from `return_items[].external_order_item_id` in a get_return response for this same RMA (list_returns → get_return → receive_return_items). It is NOT the SKU, NOT the product id, NOT the variant id, and NOT the return item `id`. Never construct, guess, transform, or reuse an identifier from anywhere else — if you do not have a get_return response for this RMA, call get_return first. BUNDLES — a `return_items[]` line that carries `bundled_items[]` is a bundle, and its own `external_order_item_id` CANNOT be received (the upstream rejects it with "Bundle item cannot be received directly"). For a bundle, send one entry per arrived COMPONENT using that component's `bundled_items[].external_id` instead. PARTIAL receiving is supported and is the normal case: send only the items that actually arrived — a subset of the RMA, or a single component of a bundle. Later arrivals go in a separate call as their own receiving batch. Never claim that receiving part of an RMA or part of a bundle is unsupported, and never redirect the user to the AfterShip admin UI for it. This tool is NOT idempotent: every call records an ADDITIONAL receiving batch, so calling it twice double-counts the received quantity and corrupts the merchant's inventory. There is no un-receive tool. Never retry it because a previous response looked unclear — call get_return and check the existing receivings instead. `gradings` describe a physical inspection you cannot perform. Only send a grade the user explicitly stated, together with the quantity they stated. Never default a grade, never infer one from the return reason, notes, or photos, and never decide on your own whether an item should be restocked. Omit `gradings` entirely when the user has not graded the items. Show the user a summary (which RMA, each item, the quantity, and any grades) and get their explicit confirmation before calling. Receiving items does not resolve or refund the return — never tell the user or the shopper that a refund has been issued. Returns the receiving batch: `{ id, items: [{ external_id, received_at, quantity, gradings }], created_at, updated_at }`. Note the response key is `external_id`, not `external_order_item_id`.
receive_return_items
Reject ONE submitted return (RMA), moving it to `rejected` and recording the merchant's reason. Requires an `rma_number` obtained from list_returns or get_return — never guess or construct one. Precondition: the RMA must currently be `submitted` (Pending approval). The RMA lifecycle cannot skip steps: submitted → approved → received → resolved, or submitted → rejected. Call get_return first to verify the current state instead of assuming it. `reject_reason` is required and MUST come from the user. Never infer the reason from context, never invent one, and never paraphrase a guess into a reason — if the user has not stated why the return is being rejected, ask them and wait for the answer. The reason is stored on the RMA and may be shown to the shopper. This is a write that this server cannot undo — there is no un-reject tool. Show the user a summary (which RMA, the state change, and the exact reason text you are about to send, verbatim) and get their explicit confirmation before calling. Returns `{ rma_number, rma_status, note }`. `note` is null on a normal success; when the upstream does not echo the new state, `rma_status` is null and `note` says the action was executed and to read the current state via get_return instead of retrying. Render `rma_status` as its label, never the raw code: `submitted`→Pending approval, `approved`→Approved, `done`→Resolved, `rejected`→Rejected, `expired`→Expired.
reject_return
Permanently delete ONE return allowlist rule by its `id`. The `id` comes from list_return_allowlist and from nowhere else. It is NOT a rule condition, a rule value, an order number, an email, or an RMA number. If the user describes the rule in words ("drop the VIP email rule"), call list_return_allowlist FIRST to resolve the `id`; if several rules match, show them and let the user choose — never pick one silently and never construct or guess an id (List→Write). Before calling, show the user the rule that is about to be deleted — its `condition`, its `operator` and its `values` exactly as list_return_allowlist returned them — and get their explicit confirmation. Deletion is permanent and this tool cannot undo it; recreating the rule afterwards requires add_return_allowlist.
remove_return_allowlist
Delete ONE return blocklist rule by its `id`. The `id` comes from list_return_blocklist and from nowhere else. It is NOT an order number, an RMA number, a customer email, or the rule value. If the user describes the rule in words ("drop the block on that SKU"), call list_return_blocklist FIRST to resolve the `id`; if several rules match, list the candidates and let the user choose — never pick one silently, and never guess or construct an id (List→Write). Before calling, show the user the rule that is about to be deleted — the `condition`, the `operator` and the `values` returned by list_return_blocklist — and get their explicit confirmation. Effect: the orders, items or customers that this rule was blocking become able to start a return again immediately. This tool cannot undo itself; recreating the rule afterwards requires add_return_blocklist.
remove_return_blocklist
Mark ONE return (RMA) as resolved — the return is finished and closed. Requires an `rma_number` obtained from list_returns or get_return — never guess or construct one. Precondition: the RMA must already have been processed — approved, and its items received. The RMA lifecycle cannot skip steps: submitted → approved → received → resolved, or submitted → rejected. Call get_return first to verify the current state and the receivings instead of assuming it. Resolution is refund-only today (refund to the original payment method, or store credit). Exchange is NOT supported by this tool — never tell the user or the shopper that an exchange has been arranged, shipped, or completed. This is a write that this server cannot undo — there is no reopen tool. Show the user a summary (which RMA, the state change, and that the return will be closed) and get their explicit confirmation before calling. Report only the state this tool returns; do not claim that money has actually moved or that the shopper has been refunded. Returns `{ rma_number, rma_status, note }`. `note` is null on a normal success; when the upstream does not echo the new state, `rma_status` is null and `note` says the action was executed and to read the current state via get_return instead of retrying. On success `rma_status` is `done`, which is displayed as Resolved. Render `rma_status` as its label, never the raw code: `submitted`→Pending approval, `approved`→Approved, `done`→Resolved, `rejected`→Rejected, `expired`→Expired.
resolve_return
Re-activate tracking for ONE shipment that has stopped being tracked. Requires the shipment `id` (the `tracking_id` from list_shipments) — never a tracking number. Only shipments in a retrackable state (typically `Expired`) can be retracked; shipments already in a final state are rejected by the upstream. Check the current status with get_shipment first, tell the user which shipment you are about to retrack, and get their confirmation. A shipment can be retracked at most 3 times in total; the 4th attempt is rejected by the upstream, so do not retry this call repeatedly after a failure. Returns the shipment detail after retracking.
retrack_shipment
Update editable fields on ONE shipment. Requires the shipment `id` (the `tracking_id` from list_shipments) — never a tracking number or order number. Send only the fields you intend to change; everything you omit is left untouched. Two fields are REPLACE-not-merge: `customers` and `shipment_tags` overwrite the whole array, so read the current values with get_shipment first and send the full intended list. That read-merge-write step is an internal mechanic: perform it, but do not lecture the user about the field being overwritten — confirm the resulting list instead. The exception is real data loss: if existing tags or customers would be dropped, name them and confirm first. Before calling, show the user exactly what will change (which shipment, which field, old → new) and get their confirmation; for customer name / email / phone changes confirm the exact new value verbatim. Do not guess values the user did not state. Returns the updated shipment detail.
update_shipment
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.