Developer reference

Nexa Commerce API v1

A REST API for a fictional B2B commerce platform, covering customers, products, orders, payments, shipments, and webhooks.

25HTTP operations
6core resources
7order states
3.1OpenAPI spec version

Purpose of this work sample

Demonstrate senior-level technical writing skills across API information architecture, developer onboarding, resource reference, reusable API conventions, error documentation, business workflows, and integration guidance.

Fictional product and API created for demonstration purposes. No real credentials, customer data, or production endpoints are represented.

01

Product & API overview

Nexa Commerce is a fictional cloud-based B2B commerce platform. Its REST API covers customer, product, order, payment, shipment, and webhook integrations.

The API follows a practical business flow: a customer portal creates an order, payment is recorded, fulfillment progresses through shipment states, and webhooks keep downstream systems synchronized.

Audience

Backend developers, integration engineers, and solution architects connecting an ERP, storefront, or fulfillment system to Nexa Commerce.

Base URL

https://api.nexacommerce.example.com/v1

Core resources

ResourcePurposeRelationship
CustomerBuyer or account profileCustomer → Orders
ProductSellable catalog itemProduct → Order items
OrderCommercial transactionOrder → Items / Payments / Shipments
PaymentPayment attemptPayment → Order
ShipmentFulfillment movementShipment → Order
WebhookEvent subscriptionWebhook → Events
02

Getting started

Authentication

Send a bearer token with every authenticated request. Requests and responses use JSON.

curl https://api.nexacommerce.example.com/v1/customers \
  -H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
  -H "Accept: application/json"

Create your first customer

curl -X POST https://api.nexacommerce.example.com/v1/customers \
  -H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"name":"Acme Industrial Supplies","email":"ops@acme.example"}'
03

API conventions

Pagination

Collection endpoints use cursor-based pagination. Treat the cursor as opaque — don't decode or construct it manually.

GET /orders?limit=25&cursor=eyJjcmVhdGVkX2F0Ijoi...

{
  "data": [ ... ],
  "pagination": { "limit": 25, "next_cursor": "..." }
}

Sorting and filtering

The default sort is -created_at. Resource-specific filters combine with logical AND. created_after and created_before accept RFC 3339 timestamps.

Idempotency

Order and payment creation accept an Idempotency-Key header so retries are safe to send.

04

Resource model

Nexa Commerce models commerce as a small set of connected resources.

CUSTOMER  1 ───────── N  ORDER
                         │
                         ├── 1:N  ORDER ITEMS ── N:1 ── PRODUCT
                         ├── 1:N  PAYMENTS
                         └── 1:N  SHIPMENTS

Resource snapshots

Order items preserve the product SKU, name, and unit price at the time of purchase, so later catalog changes never rewrite historical orders.

Identifier patterns

ResourceIdentifier prefix
Customercus_...
Productprod_...
Orderord_...
Order itemitem_...
Paymentpay_...
Shipmentshp_...
Webhookwh_...
05

Order lifecycle

The order state model makes business transitions explicit rather than implicit in application code.

DRAFT
  │
  ▼
PENDING ─────────────► CANCELLED
  │
  ▼
PAID
  │
  ▼
PROCESSING
  │
  ▼
SHIPPED
  │
  ▼
DELIVERED
State rule — delivered and cancelled orders can't be edited. An invalid state transition returns 409 Conflict with code INVALID_STATE.

Cancellation is a business action with side effects, not a data deletion — so the API models it as POST /orders/{orderId}/cancel rather than DELETE.

06

Complete endpoint reference

All 25 operations in Nexa Commerce v1, grouped by resource. Each entry follows the same order: method and path, purpose, parameters, then a sample request and response.

Customers 5 operations

POST/customers

Create a customer.

Parameters
NameTypeRequiredDescription
bodyobjectYesname and email are required.

Response: 201 Created

Request

{
  "name": "Acme Industrial Supplies",
  "email": "ops@acme.example",
  "phone": "+1-555-0100"
}

Response

{
  "id": "cus_01HZX8M4Y7",
  "name": "Acme Industrial Supplies",
  "email": "ops@acme.example",
  "status": "active"
}
GET/customers

List customers.

Parameters
NameTypeRequiredDescription
limitintegerNo1–100; default 25.
cursorstringNoOpaque pagination cursor.
statusenumNoactive, inactive, suspended.
emailstringNoExact email filter.
external_idstringNoExact external identifier.
created_afterstringNoRFC 3339 timestamp.
created_beforestringNoRFC 3339 timestamp.

Response: 200 OK

Response

{
  "data": [
    { "id": "cus_01HZX8M4Y7", "name": "Acme Industrial Supplies", "email": "ops@acme.example" }
  ],
  "pagination": { "limit": 25, "next_cursor": null }
}
GET/customers/{customerId}

Retrieve a customer.

Parameters
NameTypeRequiredDescription
customerIdstringYesCustomer identifier matching cus_...

Response: 200 OK

{
  "id": "cus_01HZX8M4Y7",
  "name": "Acme Industrial Supplies",
  "email": "ops@acme.example",
  "status": "active"
}
PATCH/customers/{customerId}

Update a customer.

Parameters
NameTypeRequiredDescription
customerIdstringYesCustomer identifier.
bodyobjectYesAny mutable customer field.

Response: 200 OK

Request

{
  "phone": "+1-555-0199",
  "status": "active"
}

Response

{
  "id": "cus_01HZX8M4Y7",
  "name": "Acme Industrial Supplies",
  "phone": "+1-555-0199",
  "status": "active"
}
DELETE/customers/{customerId}

Delete a customer.

Parameters
NameTypeRequiredDescription
customerIdstringYesCustomer identifier.

Response: 204 No Content — no response body.

Products 4 operations

POST/products

Create a product.

Parameters
NameTypeRequiredDescription
bodyobjectYessku, name, unit_price, and currency are required.

Response: 201 Created

Request

{
  "sku": "IND-1001",
  "name": "Industrial Pump",
  "description": "Standard B2B pump",
  "unit_price": 125.00,
  "currency": "USD"
}

Response

{
  "id": "prod_01HZX9A2K1",
  "sku": "IND-1001",
  "name": "Industrial Pump",
  "status": "active",
  "unit_price": 125.00,
  "currency": "USD"
}
GET/products

List products.

Parameters
NameTypeRequiredDescription
limitintegerNo1–100; default 25.
cursorstringNoOpaque pagination cursor.
statusenumNoactive, inactive, discontinued.
skustringNoExact SKU filter.
searchstringNoSearch product name or description.
created_afterstringNoRFC 3339 timestamp.
created_beforestringNoRFC 3339 timestamp.

Response: 200 OK

{
  "data": [
    { "id": "prod_01HZX9A2K1", "sku": "IND-1001", "name": "Industrial Pump", "status": "active" }
  ],
  "pagination": { "limit": 25, "next_cursor": null }
}
GET/products/{productId}

Retrieve a product.

Parameters
NameTypeRequiredDescription
productIdstringYesProduct identifier matching prod_...

Response: 200 OK

{
  "id": "prod_01HZX9A2K1",
  "sku": "IND-1001",
  "name": "Industrial Pump",
  "status": "active",
  "unit_price": 125.00,
  "currency": "USD"
}
PATCH/products/{productId}

Update a product.

Parameters
NameTypeRequiredDescription
productIdstringYesProduct identifier.
bodyobjectYesMutable product fields.

Response: 200 OK

Request

{
  "name": "Industrial Pump — Gen 2",
  "unit_price": 139.00
}

Response

{
  "id": "prod_01HZX9A2K1",
  "sku": "IND-1001",
  "name": "Industrial Pump — Gen 2",
  "unit_price": 139.00,
  "currency": "USD"
}

Orders 5 operations

POST/orders

Create an order.

Parameters
NameTypeRequiredDescription
Idempotency-KeyheaderYes16–255 characters; reuse it for safe retries.
bodyobjectYescustomer_id, currency, items, billing_address, and shipping_address are required.

Response: 201 Created

Request

{
  "customer_id": "cus_01HZX8M4Y7",
  "currency": "USD",
  "items": [
    { "product_id": "prod_01HZX9A2K1", "quantity": 10 }
  ],
  "billing_address": {
    "line1": "100 Market Street",
    "city": "Austin",
    "state": "TX",
    "postal_code": "78701",
    "country": "US"
  },
  "shipping_address": { "...": "..." }
}

Response

{
  "id": "ord_01HZXA6D3P",
  "customer_id": "cus_01HZX8M4Y7",
  "status": "pending",
  "currency": "USD",
  "subtotal": 1250.00,
  "tax": 100.00,
  "shipping_cost": 25.00,
  "total": 1375.00
}
GET/orders

List orders.

Parameters
NameTypeRequiredDescription
limitintegerNo1–100; default 25.
cursorstringNoOpaque pagination cursor.
customer_idstringNoFilter by customer.
statusenumNodraft, pending, paid, processing, shipped, delivered, cancelled.
min_totalnumberNoMinimum order total.
max_totalnumberNoMaximum order total.
created_afterstringNoRFC 3339 timestamp.
created_beforestringNoRFC 3339 timestamp.
sortstringNocreated_at or -created_at.

Response: 200 OK

{
  "data": [
    { "id": "ord_01HZXA6D3P", "customer_id": "cus_01HZX8M4Y7", "status": "pending", "total": 1375.00 }
  ],
  "pagination": { "limit": 25, "next_cursor": null }
}
GET/orders/{orderId}

Retrieve an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier matching ord_...

Response: 200 OK

{
  "id": "ord_01HZXA6D3P",
  "customer_id": "cus_01HZX8M4Y7",
  "status": "pending",
  "currency": "USD",
  "total": 1375.00,
  "items": []
}
PATCH/orders/{orderId}

Update an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.
bodyobjectYesMutable fields such as addresses and metadata.

Response: 200 OK

Request

{
  "shipping_address": {
    "line1": "200 Congress Ave",
    "city": "Austin",
    "state": "TX",
    "postal_code": "78701",
    "country": "US"
  }
}

Response

{
  "id": "ord_01HZXA6D3P",
  "status": "pending",
  "shipping_address": {
    "line1": "200 Congress Ave",
    "city": "Austin"
  }
}
POST/orders/{orderId}/cancel

Cancel an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.

Response: 200 OK

{
  "id": "ord_01HZXA6D3P",
  "status": "cancelled",
  "updated_at": "2026-09-12T09:02:00Z"
}

Order items 3 operations

POST/orders/{orderId}/items

Add an item to an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.
bodyobjectYesproduct_id and quantity are required.

Response: 201 Created

Request

{
  "product_id": "prod_01HZX9A2K1",
  "quantity": 5
}

Response

{
  "id": "item_01HZXB1N5K",
  "product_id": "prod_01HZX9A2K1",
  "sku": "IND-1001",
  "name": "Industrial Pump",
  "quantity": 5,
  "unit_price": 125.00,
  "subtotal": 625.00
}
PATCH/orders/{orderId}/items/{itemId}

Update an order item's quantity.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.
itemIdstringYesOrder item identifier.
bodyobjectYesquantity is mutable while the order is editable.

Response: 200 OK

Request

{ "quantity": 8 }

Response

{
  "id": "item_01HZXB1N5K",
  "quantity": 8,
  "unit_price": 125.00,
  "subtotal": 1000.00
}
DELETE/orders/{orderId}/items/{itemId}

Remove an item from an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.
itemIdstringYesOrder item identifier.

Response: 204 No Content — no response body.

Payments 3 operations

POST/orders/{orderId}/payments

Create a payment attempt for an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.
Idempotency-KeyheaderYes16–255 characters; reuse it for retries.
bodyobjectYesamount, currency, method, and provider.

Response: 201 Created

Request

{
  "amount": 1375.00,
  "currency": "USD",
  "method": "purchase_order",
  "provider": "internal"
}

Response

{
  "id": "pay_01HZXC1M6N",
  "order_id": "ord_01HZXA6D3P",
  "amount": 1375.00,
  "currency": "USD",
  "status": "processing",
  "method": "purchase_order",
  "provider": "internal"
}
GET/orders/{orderId}/payments

List payments for an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.
limitintegerNo1–100; default 25.
cursorstringNoOpaque pagination cursor.
statusenumNopending, processing, succeeded, failed, cancelled.
created_afterstringNoRFC 3339 timestamp.
created_beforestringNoRFC 3339 timestamp.

Response: 200 OK

{
  "data": [
    { "id": "pay_01HZXC1M6N", "order_id": "ord_01HZXA6D3P", "status": "processing", "amount": 1375.00 }
  ],
  "pagination": { "limit": 25, "next_cursor": null }
}
GET/payments/{paymentId}

Retrieve a payment.

Parameters
NameTypeRequiredDescription
paymentIdstringYesPayment identifier matching pay_...

Response: 200 OK

{
  "id": "pay_01HZXC1M6N",
  "order_id": "ord_01HZXA6D3P",
  "status": "succeeded",
  "amount": 1375.00,
  "currency": "USD"
}

Shipments 2 operations

GET/orders/{orderId}/shipments

List shipments for an order.

Parameters
NameTypeRequiredDescription
orderIdstringYesOrder identifier.
limitintegerNo1–100; default 25.
cursorstringNoOpaque pagination cursor.
statusenumNopending, processing, shipped, delivered, cancelled.
created_afterstringNoRFC 3339 timestamp.
created_beforestringNoRFC 3339 timestamp.

Response: 200 OK

{
  "data": [
    { "id": "shp_01HZXD7K3R", "order_id": "ord_01HZXA6D3P", "status": "shipped", "carrier": "Nexa Logistics", "tracking_number": "NX123456789" }
  ],
  "pagination": { "limit": 25, "next_cursor": null }
}
GET/shipments/{shipmentId}

Retrieve a shipment.

Parameters
NameTypeRequiredDescription
shipmentIdstringYesShipment identifier matching shp_...

Response: 200 OK

{
  "id": "shp_01HZXD7K3R",
  "order_id": "ord_01HZXA6D3P",
  "status": "shipped",
  "carrier": "Nexa Logistics",
  "tracking_number": "NX123456789"
}

Webhooks 3 operations

POST/webhooks

Create a webhook subscription.

Parameters
NameTypeRequiredDescription
bodyobjectYesurl and events are required; the URL must use HTTPS.

Response: 201 Created

Request

{
  "url": "https://erp.acme.example/webhooks/nexa",
  "events": ["order.paid", "order.shipped", "order.delivered"]
}

Response

{
  "id": "wh_01HZXE3P2D",
  "url": "https://erp.acme.example/webhooks/nexa",
  "events": ["order.paid", "order.shipped", "order.delivered"],
  "status": "active"
}
GET/webhooks

List webhook subscriptions.

Parameters
NameTypeRequiredDescription
limitintegerNo1–100; default 25.
cursorstringNoOpaque pagination cursor.
statusenumNoactive, inactive.
sortstringNocreated_at or -created_at.

Response: 200 OK

{
  "data": [
    { "id": "wh_01HZXE3P2D", "url": "https://erp.acme.example/webhooks/nexa", "status": "active" }
  ],
  "pagination": { "limit": 25, "next_cursor": null }
}
DELETE/webhooks/{webhookId}

Delete a webhook subscription.

Parameters
NameTypeRequiredDescription
webhookIdstringYesWebhook identifier matching wh_...

Response: 204 No Content — no response body.

07

Webhooks

Webhooks let downstream systems react to commerce events without repeatedly polling the API.

Recommended consumer pattern

  1. Verify the delivery's security mechanism.
  2. Parse the event type and resource identifier.
  3. Persist the event or idempotency key before processing.
  4. Return a successful response quickly.
  5. Perform long-running work asynchronously.
Delivery guarantee — webhook delivery is at-least-once. Make event handling idempotent on your end.
08

Errors & troubleshooting

Errors use a stable envelope so clients can handle failures consistently across every resource.

{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "One or more parameters are invalid.",
    "request_id": "req_01HZQ2M8F1",
    "details": [
      { "code": "INVALID_ENUM_VALUE", "message": "status must be active, inactive, or suspended.", "param": "status", "location": "query" },
      { "code": "VALUE_OUT_OF_RANGE", "message": "limit must be between 1 and 100.", "param": "limit", "location": "query" }
    ]
  }
}

Status code guide

HTTPMeaningTypical action
400Malformed or unsupported requestCorrect syntax or parameters.
401Authentication failedCheck the bearer token.
403Permission deniedCheck required permissions.
404Resource not foundVerify the identifier and environment.
409Business state conflictRefresh state; retry only if valid.
422Valid shape, failed validationCorrect field-level validation errors.
429Rate limit exceededWait for Retry-After and retry.
500 / 503Server or service failureRetry with backoff when appropriate.

Rate limiting

The API permits 60 requests per minute. Responses may include X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After.

09

End-to-end integration walkthrough

A realistic integration combines synchronous API calls with asynchronous events.

1  POST /customers
        │
        ▼
2  POST /orders
        │
        ▼
3  POST /orders/{orderId}/payments
        │
        ├──── webhook: order.paid ────► ERP
        │
        ▼
4  GET /orders/{orderId}/shipments
        │
        └──── webhook: order.delivered ─► ERP

Integration guidance

Use API responses for immediate state and webhooks for asynchronous state changes. Avoid building critical workflows around polling alone.

10

Documentation approach

Endpoint-first reference

Every endpoint follows the same reading order: method and path, then purpose, parameters, request, and response — so a reader can scan and compare operations quickly.

Centralized conventions

Pagination, sorting, filtering, validation, errors, rate limits, and authentication are each defined once as API-wide conventions rather than repeated per endpoint.

Business-aware guidance

The documentation explains behavior that can't be inferred from HTTP verbs alone — order cancellation, editable order states, payment processing, and historical item snapshots.

Machine-readable foundation

A companion OpenAPI 3.1 specification provides reusable parameters, schemas, responses, security definitions, and resource-specific collection schemas.

—

Appendix: API coverage

Resource areaOperations
Customers5 — create, list, retrieve, update, delete
Products4 — create, list, retrieve, update
Orders5 — create, list, retrieve, update, cancel
Order items3 — add, update, remove
Payments3 — create, list by order, retrieve
Shipments2 — list by order, retrieve
Webhooks3 — create, list, delete
Total25 HTTP operations