Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions .agents/skills/ep-example-authoring/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
name: ep-example-authoring
description: Author or update EasyPost examples using repository conventions for directory structure, endpoint/action naming, versioning, placeholder values, and minimal runnable snippet shape across docs, guides, and responses.
---

# EasyPost Example Authoring Skill

Use this skill when creating or updating examples in this repository.

## Purpose

Keep examples consistent across languages and versions while preserving the repo's docs-site ingestion conventions.

## Scope

This skill applies to:

- `official/docs/*`
- `official/guides/*`
- `official/docs/responses/*`

## Source Of Truth Priority

When conventions conflict, use this order:

1. Existing `official/docs/curl/current` endpoint/action directory and filename layout.
2. Existing `official/docs/<language>/current` precedent for that endpoint.
3. `README.md` conventions in the Development section.
4. Fixture-aligned values from `official/fixtures`.

## Repository Structure Rules

- `official/docs/<language>/current` is the authoritative, latest snippet set used by downstream sites.
- `official/docs/<language>/vN` directories preserve old major-version examples.
- `official/docs/responses` is not versioned and does not have a `current` directory.
- `official/guides` contains guide-specific examples and payload assets.

## Endpoint Directory And Filename Rules

### Docs snippets

- Place snippets under `official/docs/<language>/current/<endpoint>/<action>.<ext>`.
- Endpoint directories use kebab-case path names, matching curl endpoint folder names.
- Action filenames use kebab-case and should match curl script stem.

Examples:

- `official/docs/curl/current/addresses/create-and-verify.sh`
- `official/docs/node/current/addresses/create-and-verify.js`
- `official/docs/python/current/scan-form/list.py`

### Response snippets

- Place responses under `official/docs/responses/<endpoint>/<action>.json`.
- Keep response endpoint/action naming aligned with curl endpoint/action naming.

Examples:

- `official/docs/responses/addresses/create.json`
- `official/docs/responses/rates/retrieve-stateless.json`

## Snippet Content Rules

Each example should be minimally viable and runnable as-is except placeholders.

Required shape:

1. Import the library.
2. Instantiate client with `EASYPOST_API_KEY` placeholder.
3. Perform one focused API call.
4. Print/log the result.

Keep snippets:

- Small and focused.
- Free of unrelated setup, abstractions, or control flow.
- Consistent with existing naming and call style in that language.

## Placeholder Rules

- Use `EASYPOST_API_KEY` for API key placeholder.
- Use object ID placeholders by prefix plus ellipsis, e.g. `adr_...`, `shp_...`, `sf_...`, `ca_...`.
- Use open-source/non-PII sample data.
- Prefer fixture-aligned values when possible.

## Language-Specific Precedent Notes

Use existing files in each language's `current` directory as direct style precedent.

- Curl: one command per file, `curl -X ...`, JSON body inline, API key via `-u "EASYPOST_API_KEY":`.
- Node: CommonJS `require`, async IIFE, `console.log(...)` output.
- Python: module import + direct call sequence + `print(...)`.
- Ruby: `require 'easypost'`, client creation, call, `puts` output.
- PHP: instantiate client, execute call, `echo` output.
- C#: async `Main`, typed parameters object, JSON serialization to console.
- Go: helper function snippet style, make call, `fmt.Println(...)`.
- Java: class-per-file examples with `main`, but package naming may intentionally differ from folder name for historical consistency.

Java package caution:

- Do not auto-rename package declarations to match folder names.
- Follow existing local precedent for that endpoint set.
- Some endpoint folders intentionally map to shared package namespaces.

## Versioning Workflow

When a client library releases a new major version:

1. Copy `official/docs/<language>/current` to `official/docs/<language>/v<previous_major>`.
2. Update only `current` for latest major syntax/usage changes.
3. Keep endpoint/action coverage and naming consistent between versions unless API/library behavior requires divergence.

## Consistency Checklist Before Commit

1. Filename and folder parity against curl `current` action names.
2. Response filename is action-only (no endpoint prefix).
3. Snippet uses minimal runnable structure and `EASYPOST_API_KEY`.
4. Placeholder IDs follow expected prefixes.
5. New data is non-PII and fixture-aligned where possible.
6. `current` directories remain present for all language docs.

## Optional Verification Commands

```bash
# Ensure required current dirs still exist
bash test/ensure-current-dirs-exist.sh

# Spot-check endpoint/action parity shape
find official/docs/curl/current -maxdepth 2 -type f | head
find official/docs/responses -maxdepth 2 -type f | head
```

## Anti-Patterns

- Endpoint-prefixed response filenames.
- Adding extra helper frameworks or architecture in simple snippets.
- Introducing language-specific style drift not already present in that language's `current` precedent.
- Changing historical version directories when the change should be only in `current`.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![CI](https://github.com/EasyPost/examples/workflows/CI/badge.svg)](https://github.com/EasyPost/examples/actions?query=workflow%3ACI)

5,000+ code examples for using the EasyPost API across 7+ programming languages.
3,000+ code examples for using the EasyPost API across 7+ programming languages.

## Project Structure

Expand Down Expand Up @@ -35,18 +35,18 @@ Once installed, run an example like you would any other script or tool for that

### Conventions

When creating new doc snippets, we follow a few conventions:
When creating or updating examples, follow these baseline rules:

1. The example should be minimally viable - only include what is absolutely necessary to run the example. This ensures our example are simple, straightforward, and focused. An example is importing the lib, creating a client, calling the function with the data, printing the object to console.
2. With over 5,000 examples, it's paramount that our examples remain consistent. This is true across languages, versions (with the exception of syntax changes), and different functions. The examples have strong precedent, convention, and consistency - these should be maintained into the future.
3. When trying to determine what data to use for examples, it's probably best to use the same or similar data that our client library fixtures used during implementation. All of our client libraries use the same fixture data in tests ensuring consistency there, the same can (and should) be done for examples.
1. You must use open source data (addresses, names, etc) - something that's not personally identifiable to a real person or business. Using EasyPost addresses or addresses of well-known public landmarks are good options
4. Examples must run "as-is" with no alterations (except for placeholder IDs and API keys). This ensures each of our examples can be quickly copy and pasted by users to try functionality quickly while they onboard, ensuring a great user experience.
1. Keep snippets minimally viable and focused: import the library, create a client, perform one clear API call, and print/log the result.
2. Preserve cross-language and cross-version consistency. Use existing `official/docs/<language>/current` snippets as precedent and keep endpoint/action naming aligned with curl.
3. Use fixture-aligned, open-source sample data only. Do not include real-person or real-business PII.
4. Examples should run as-is with no edits other than replacing placeholder API keys and object IDs.
5. For full standards (directory layout, naming, responses, placeholders, and versioning), see [`.agents/skills/ep-example-authoring/SKILL.md`](.agents/skills/ep-example-authoring/SKILL.md).

### New Major Versions

When the client libraries have a new major version released, we need to create a new versioned directory in every language directory for this project. This ensures that users who do not upgrade client libraries still have a set of examples specific to their version to reference. When a new major version is released, copy the `current` directory and rename it to the previous major version. Then, make any necessary changes to the `current` directory docs (usually syntax changes if applicable). Rinse and repeat for every language directory.

### Importance of `current` Directory

Our docs (and marketing) websites submodule this `examples` repo so we can pull in stable example docs at various milestones. We use the `current` language directory to pull the doc snippets during the build process (the versioned directories are then retained for reference). As such, it's imperative that the `current` directory remains the most up-to-date set of docs and present in each langauge directory we have. We have tests in this project to ensure as much.
Our docs website submodule this `examples` repo so we can pull in stable example docs at various milestones. We use the `current` language directory to pull the doc snippets during the build process (the versioned directories are then retained for reference). As such, it's imperative that the `current` directory remains the most up-to-date set of docs and present in each langauge directory we have. We have tests in this project to ensure as much.
40 changes: 40 additions & 0 deletions official/docs/responses/claims/cancel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"approved_amount": null,
"attachments": [
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/e85d5ec7bd2f44bcbfecaddd7b8fbdc9.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/dc795c3604cb40e7a6fe37762cbff8de.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/01403d1550d44fd3a5dde2fc7e0c5314.png"
],
"check_delivery_address": null,
"contact_email": "test@example.com",
"created_at": "2025-05-12T19:08:10Z",
"description": "Test description",
"history": [
{
"status": "cancelled",
"status_detail": "Claim cancellation was requested.",
"timestamp": "2025-05-12T19:08:11Z"
},
{
"status": "submitted",
"status_detail": "Claim was created.",
"timestamp": "2025-05-12T19:08:10Z"
}
],
"id": "clm_09d81405ad494f6ca8bcbf884f207bc4",
"insurance_amount": "100.00",
"insurance_id": "ins_2f140b24c17d4e66a3223d621ef4beee",
"mode": "test",
"object": "Claim",
"payment_method": "easypost_wallet",
"recipient_name": null,
"requested_amount": "100.00",
"salvage_value": null,
"shipment_id": "shp_11f0e96492bd4e03918cb34021d49521",
"status": "cancelled",
"status_detail": "Claim cancellation was requested.",
"status_timestamp": "2025-05-12T19:08:11Z",
"tracking_code": "9405500208303109888333",
"type": "damage",
"updated_at": "2025-05-12T19:08:11Z"
}
35 changes: 35 additions & 0 deletions official/docs/responses/claims/create.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"approved_amount": null,
"attachments": [
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/a915d0e238074fff9729afa1bfb87a0e.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/3020f31a57374dc3ace477f7a4ec860d.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/88aada9e505f4e77bd6060710d78e497.png"
],
"check_delivery_address": null,
"contact_email": "test@example.com",
"created_at": "2025-05-12T19:08:04Z",
"description": "Test description",
"history": [
{
"status": "submitted",
"status_detail": "Claim was created.",
"timestamp": "2025-05-12T19:08:04Z"
}
],
"id": "clm_09d89e88a0c943d59018bc26b041c41c",
"insurance_amount": "100.00",
"insurance_id": "ins_da31156b6335407da23ee06fa2fe8a28",
"mode": "test",
"object": "Claim",
"payment_method": "easypost_wallet",
"recipient_name": null,
"requested_amount": "100.00",
"salvage_value": null,
"shipment_id": "shp_531f76e4a4de491183f5cabb738cb828",
"status": "submitted",
"status_detail": "Claim was created.",
"status_timestamp": "2025-05-12T19:08:04Z",
"tracking_code": "9405500208303109888319",
"type": "damage",
"updated_at": "2025-05-12T19:08:04Z"
}
40 changes: 40 additions & 0 deletions official/docs/responses/claims/list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"claims": [
{
"approved_amount": null,
"attachments": [
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/2384384e13a14d2eb6513b6f4fa3e7db.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/695260b95d0743a284bf0bf1eea7421c.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/f369b8e2ce894e798c14850684fd16fe.png"
],
"check_delivery_address": null,
"contact_email": "test@example.com",
"created_at": "2025-05-12T19:08:07Z",
"description": "Test description",
"history": [
{
"status": "submitted",
"status_detail": "Claim was created.",
"timestamp": "2025-05-12T19:08:07Z"
}
],
"id": "clm_09d891bf4d9045b48cb64e0319338f1c",
"insurance_amount": "100.00",
"insurance_id": "ins_e5d632db2ede497e83de78e0c6cc5a60",
"mode": "test",
"object": "Claim",
"payment_method": "easypost_wallet",
"recipient_name": null,
"requested_amount": "100.00",
"salvage_value": null,
"shipment_id": "shp_1152edb694924af2a5ca3c5d4fba45d3",
"status": "submitted",
"status_detail": "Claim was created.",
"status_timestamp": "2025-05-12T19:08:07Z",
"tracking_code": "9405500208303109888326",
"type": "damage",
"updated_at": "2025-05-12T19:08:07Z"
}
],
"has_more": true
}
35 changes: 35 additions & 0 deletions official/docs/responses/claims/retrieve.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"approved_amount": null,
"attachments": [
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/2384384e13a14d2eb6513b6f4fa3e7db.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/695260b95d0743a284bf0bf1eea7421c.png",
"https://easypost-files.s3-us-west-2.amazonaws.com/insurance/20250512/f369b8e2ce894e798c14850684fd16fe.png"
],
"check_delivery_address": null,
"contact_email": "test@example.com",
"created_at": "2025-05-12T19:08:07Z",
"description": "Test description",
"history": [
{
"status": "submitted",
"status_detail": "Claim was created.",
"timestamp": "2025-05-12T19:08:07Z"
}
],
"id": "clm_09d891bf4d9045b48cb64e0319338f1c",
"insurance_amount": "100.00",
"insurance_id": "ins_e5d632db2ede497e83de78e0c6cc5a60",
"mode": "test",
"object": "Claim",
"payment_method": "easypost_wallet",
"recipient_name": null,
"requested_amount": "100.00",
"salvage_value": null,
"shipment_id": "shp_1152edb694924af2a5ca3c5d4fba45d3",
"status": "submitted",
"status_detail": "Claim was created.",
"status_timestamp": "2025-05-12T19:08:07Z",
"tracking_code": "9405500208303109888326",
"type": "damage",
"updated_at": "2025-05-12T19:08:07Z"
}
Loading
Loading