/product-typesList product typesReturns up to 500 records in newest-first order.
operationId:listProductTypesOrganization-scoped CRUD for the canonical sellable catalog, Etsy/Shopify/Personmade listing projections, location inventory, immutable order lines, fulfillment, private assets, and append-only activity.
Open your dashboard, go to Settings, name the integration, and generate an API key. Settings keeps it, so you can expand the key's row and copy it again later.
Keep the key in a secret manager or environment variable. Never commit it.
export PERSONMADE_API_KEY='pms_…' export PERSONMADE_API_BASE='https://www.personmade.club/api/v1'
The key determines the organization automatically; no organization ID is sent.
curl --fail --silent --show-error \ -H "Authorization: Bearer $PERSONMADE_API_KEY" \ "$PERSONMADE_API_BASE/products"
curl --fail --silent --show-error \
-X POST \
-H "Authorization: Bearer $PERSONMADE_API_KEY" \
-H "Content-Type: application/json" \
--data '{"name":"Poster","description":"Archival print"}' \
"$PERSONMADE_API_BASE/product-types"Approve the type with POST /product-types/{id}/approve before filing products under it.
{"data": …}. Validation and request errors return {"error": "…"}. Deletes return HTTP 204 with no body.Generated from the same OpenAPI document served at /openapi.json.
/product-typesList product typesReturns up to 500 records in newest-first order.
operationId:listProductTypes/product-typesCreate a product typecreateProductType/product-types/{id}Get a product typegetProductType/product-types/{id}Update selected product type fieldsupdateProductType/product-types/{id}Update supplied product type fieldsPUT currently has the same partial-update semantics as PATCH.
operationId:putProductType/product-types/{id}Delete a product typedeleteProductType/product-types/{id}/approveApprove a product typeapproveProductType/product-types/{productTypeId}/etsy-configurationRead reusable Etsy configurationReturns the Etsy values inherited by this product type's mirrors, including per-shop shipping, return, and processing profile ids.
operationId:getEtsyProductTypeConfiguration/product-types/{productTypeId}/etsy-configurationCreate or replace reusable Etsy configurationValidates the category and variation mappings with Etsy, saves all type-owned mirror values, and synchronizes existing automatic mirrors.
operationId:putEtsyProductTypeConfiguration/connections/{connectionId}/etsy-policiesRead shipping, return, and processing profiles from EtsyReturns the real shop policy and processing-profile ids used to configure an Etsy product type for this connection. It refreshes the Etsy access token when necessary.
operationId:readEtsyPolicies/connections/{connectionId}/etsy-configuration-choicesRead Etsy categories and variation propertiesreadEtsyConfigurationChoices/productsList productsReturns up to 500 records in newest-first order.
operationId:listProducts/productsCreate a productA product type must be approved before products can be filed under it.
operationId:createProduct/products/{id}Get a productgetProduct/products/{id}Update selected product fieldsA product type must be approved before products can be filed under it.
operationId:updateProduct/products/{id}Update supplied product fieldsPUT currently has the same partial-update semantics as PATCH. A product type must be approved before products can be filed under it.
operationId:putProduct/products/{id}Delete a productdeleteProduct/products/{id}/approveApprove a product after it has at least 2 product photosapproveProduct/products/{id}/unapproveReturn an approved product to draftClears the approval. The product keeps its photos, listings, and catalog data; a product that is already a draft is a 409.
operationId:unapproveProduct/products/{productId}/catalogRead the complete canonical productReturns the product's return-policy reference, ordered options and values, explicit sparse variants with supply and shipping fields, personalization, reviewed media, and inventory items. A product without visible options still returns its one stable default variant.
operationId:getProductCatalog/products/{productId}/optionsAdd an ordered option axisA product can have zero to three axes. Existing variants atomically select the first supplied value, so no active variant is left invalid.
operationId:createProductOption/product-options/{id}Rename or reorder an option axisReordering also rebuilds every canonical variant selection key atomically.
operationId:updateProductOption/product-options/{id}Remove an option axisRejected if removing the axis would create duplicate variant combinations.
operationId:deleteProductOption/product-options/{optionId}/valuesAdd an option valuecreateProductOptionValue/product-option-values/{id}Rename or reorder an option valueupdateProductOptionValue/product-option-values/{id}Remove an unused option valueA value selected by any variant cannot be removed.
operationId:deleteProductOptionValue/products/{productId}/variantsCreate one explicit purchasable variantSparse combinations are valid and no Cartesian product is generated. The complete selected combination must be unique within the product.
operationId:createProductVariant/product-variants/{id}Update a variant or its complete selectionVariant UUID is stable identity; SKU is nullable, repeatable merchant data.
operationId:updateProductVariant/product-variants/{id}Remove an unmapped variantEvery product must keep at least one explicit variant.
operationId:deleteProductVariant/shipping-profilesList canonical shipping profileslistShippingProfiles/shipping-profilesCreate a canonical shipping profileA profile owns its origin and processing window. Add destination prices through its rates collection.
operationId:createShippingProfile/shipping-profiles/{id}Update a shipping profileupdateShippingProfile/shipping-profiles/{id}Delete an unused shipping profileA profile referenced by a variant cannot be deleted.
operationId:deleteShippingProfile/shipping-profiles/{profileId}/ratesList a shipping profile's destination rateslistShippingRates/shipping-profiles/{profileId}/ratesAdd a destination rateA profile can have one everywhere rate and one rate for each country.
operationId:createShippingRate/shipping-rates/{id}Delete a shipping ratedeleteShippingRate/return-policiesList canonical return policieslistReturnPolicies/return-policiesCreate a canonical return policycreateReturnPolicy/return-policies/{id}Update a return policyupdateReturnPolicy/return-policies/{id}Delete an unused return policyA policy referenced by a product cannot be deleted.
operationId:deleteReturnPolicy/shipping-profile-mappingsList shipping profile marketplace mappingslistShippingProfileMappings/shipping-profile-mappingsCreate or replace a shipping profile marketplace mappingUpserts the remote id for one canonical policy and connection. Remote ids are read from the marketplace account, not invented per listing.
operationId:putShippingProfileMapping/shipping-profile-mappings/{id}Delete a shipping-profile marketplace mappingdeleteShippingProfileMapping/return-policy-mappingsList return policy marketplace mappingslistReturnPolicyMappings/return-policy-mappingsCreate or replace a return policy marketplace mappingUpserts the remote id for one canonical policy and connection. Remote ids are read from the marketplace account, not invented per listing.
operationId:putReturnPolicyMapping/return-policy-mappings/{id}Delete a return-policy marketplace mappingdeleteReturnPolicyMapping/products/{productId}/etsy-mirrorsList a product's Etsy mirrorslistEtsyMirrors/products/{productId}/etsy-mirrorsCreate and synchronize an Etsy mirrorPersists the optional tag override and inherits all other Etsy choices from the product type. It adopts and updates a compatible Etsy listing already linked to this product; otherwise it creates a draft.
operationId:createEtsyMirror/etsy-mirrors/{listingId}Change Etsy-only choicesOnly tags and synchronization can differ from the product type.
operationId:updateEtsyMirror/etsy-mirrors/{listingId}/syncSend canonical product state to Etsy nowUses the latest product-type Etsy configuration and retains only the mirror's tag override and synchronization setting.
operationId:syncEtsyMirror/products/{productId}/customizationsAdd buyer personalizationPersonalization does not create variants. Canonical kinds are text, single_select, and file; provider validators apply narrower provider limits.
operationId:createProductCustomization/product-customizations/{id}Update buyer personalizationupdateProductCustomization/product-customizations/{id}Remove buyer personalizationdeleteProductCustomization/product-customizations/{customizationId}/choicesAdd a single-select choicecreateCustomizationChoice/product-customization-choices/{id}Update a single-select choiceupdateCustomizationChoice/product-customization-choices/{id}Remove a single-select choicedeleteCustomizationChoice/product-variants/{id}/mediaReplace a variant's ordered asset associationsreplaceVariantMedia/products/{productId}/mediaList reviewed product medialistProductMedia/products/{productId}/mediaSelect reviewed product mediaThe source ETag or checksum pins the reviewed bytes.
operationId:createProductMedia/product-media/{id}Remove product media selectiondeleteProductMedia/inventory-locationsList inventory locationsEvery organization has one required active default location.
operationId:listInventoryLocations/inventory-locationsCreate an inventory locationcreateInventoryLocation/inventory-locations/{id}Update an inventory locationThe required default location cannot be deactivated or removed.
operationId:updateInventoryLocation/inventory-locations/{id}Delete an unused non-default locationdeleteInventoryLocation/inventory-itemsList product inventory itemslistInventoryItems/inventory-itemsCreate a product inventory itemSeveral variants can reference one stock identity; this does not add bundle semantics.
operationId:createInventoryItem/inventory-items/{id}Update inventory policyupdateInventoryItem/inventory-items/{id}Delete an unused inventory itemdeleteInventoryItem/inventory-adjustmentsList the append-only inventory ledgerlistInventoryAdjustments/inventory-adjustmentsAppend an inventory quantity adjustmentSource plus idempotency_key is unique per organization.
operationId:createInventoryAdjustment/inventory-reservationsList inventory reservationslistInventoryReservations/inventory-reservationsHold available quantity for a checkoutActive, unexpired reservations reduce availability.
operationId:createInventoryReservation/inventory-reservations/{id}Release or commit an active reservationupdateInventoryReservation/inventory-availabilityRead ledger availability minus live reservationslistInventoryAvailability/listings/{listingId}/revisionsList immutable desired revisionsObserved listing_data remains separate.
operationId:listListingRevisions/listings/{listingId}/revisionsCreate a numbered provider-typed desired revisioncreateListingRevision/listing-revisions/{id}Edit or approve a draft revisionApproved revisions cannot be changed or deleted.
operationId:updateListingRevision/orders/{orderId}/linesList immutable order-line snapshotslistOrderLines/orders/{orderId}/linesCreate an immutable order-line snapshotSelected options and buyer personalization are preserved separately from the stable variant reference.
operationId:createOrderLine/fulfillments/{fulfillmentId}/linesList fulfilled order-line quantitieslistFulfillmentLines/fulfillments/{fulfillmentId}/linesApply a fulfilled quantity to one order lineTotal fulfilled quantity cannot exceed the order-line quantity.
operationId:createFulfillmentLine/connectionsList organization marketplace connectionsReturns safe connection metadata and a credentials_configured flag. Credential values are never returned.
operationId:listMarketplaceConnections/connectionsCreate an organization marketplace connectionAccepts organization-owned credentials, encrypts them before D1 storage, and excludes them from the response and activity event.
operationId:createMarketplaceConnection/connections/{id}Read safe marketplace connection metadatagetMarketplaceConnection/connections/{id}Update connection metadata or replace credentialsOmit credentials to keep the encrypted values. Supplying credentials replaces the full encrypted credential object.
operationId:updateMarketplaceConnection/connections/{id}Delete an unlinked marketplace connectionA connection still used by a listing cannot be deleted.
operationId:deleteMarketplaceConnection/connections/{id}/disconnectDisconnect and erase organization credentialsErases the encrypted credential material while preserving safe account identity and listing mappings for history and reconnection.
operationId:disconnectMarketplaceConnection/listingsList listingsReturns up to 500 records in newest-first order.
operationId:listListings/listingsCreate a listingcreateListing/listings/{id}Get a listinggetListing/listings/{id}Update selected listing fieldsupdateListing/listings/{id}Update supplied listing fieldsPUT currently has the same partial-update semantics as PATCH.
operationId:putListing/listings/{id}Delete a listingdeleteListing/ordersList ordersReturns up to 500 records in newest-first order.
operationId:listOrders/ordersCreate an ordercreateOrder/orders/{id}Get an ordergetOrder/orders/{id}Update selected order fieldsupdateOrder/orders/{id}Update supplied order fieldsPUT currently has the same partial-update semantics as PATCH.
operationId:putOrder/orders/{id}Delete an orderdeleteOrder/fulfillmentsList fulfillmentsReturns up to 500 records in newest-first order.
operationId:listFulfillments/fulfillmentsCreate a fulfillmentcreateFulfillment/fulfillments/{id}Get a fulfillmentgetFulfillment/fulfillments/{id}Update selected fulfillment fieldsupdateFulfillment/fulfillments/{id}Update supplied fulfillment fieldsPUT currently has the same partial-update semantics as PATCH.
operationId:putFulfillment/fulfillments/{id}Delete a fulfillmentdeleteFulfillment/products/{id}/assetsUpload a product assetStreams a raw binary body to private storage. Maximum size is 100 MB, rejected from Content-Length before the body is read when the client declares it. Product photos are selected for storefront publishing by default; other asset kinds remain private.
operationId:uploadProductAsset/assetsList asset metadatalistAssets/assets/{id}Download an assetAlways an attachment of type application/octet-stream, whatever the upload claimed: the stored content type is catalogue metadata, never a rendering instruction. Use /assets/{id}/view to display an image or video instead.
operationId:downloadAsset/assets/{id}Rename an assetThe filename is the only writable field. The stored object keeps the key it was written under.
operationId:renameAsset/assets/{id}Delete an asset and its stored filedeleteAsset/assets/{id}/viewView an asset inlineServes the object under its own content type, for displaying it rather than saving it. Only PNG, JPEG, GIF, WebP, AVIF, MP4, WebM, Ogg and QuickTime are served that way, always with nosniff and a sandboxing CSP; every other type falls back to the same attachment download as /assets/{id}. Answers Range requests so a video can seek, and conditional requests with a 304 so a preview is fetched once.
operationId:viewAsset/assets/{id}/watermarkedDownload a watermarked copyAsks Cloudflare Images to tile Personmade's proof mark over an eligible JPEG, PNG, or WebP and returns the WebP immediately. The private original remains unchanged and no derivative is stored.
operationId:downloadWatermarkedAsset/eventsList the latest 500 app eventsReturns the append-only activity stream in newest-first order.
operationId:listEventslisting_data, order_data, and fulfillment_data are JSON objects, not encoded JSON strings. All timestamps represent UTC instants. The API returns Unix epoch milliseconds; order and fulfillment writes accept those or RFC 3339 UTC strings ending in Z.
Shipping profiles, destination rates, and return policies are canonical shop records. Products reference one return policy, and physical variants reference one shipping profile. A variant's supply_policy is stocked, made_to_order, or made_to_request. Stocked variants need an inventory item; made-to-order variants need a positive made_to_order_limit; made-to-request variants are not directly purchasable.
Marketplace mapping endpoints store the remote ID that a connected shop uses for the same canonical policy.
Send the file as the raw request body with its actual Content-Type, an X-Filename header, and a valid kind query parameter. Assets can be up to 100 MB.
curl -X POST \ -H "Authorization: Bearer $PERSONMADE_API_KEY" \ -H "Content-Type: image/png" \ -H "X-Filename: artwork.png" \ --data-binary @artwork.png \ "$PERSONMADE_API_BASE/products/PRODUCT_ID/assets?kind=source"
Eligible JPEG, PNG, and WebP assets can be stamped on demand with your shop's proof mark, which carries your organization's name. Cloudflare Images returns the stamped copy immediately, usually as WebP and sometimes as JPEG or PNG when it judges that a better fit for the source; the private original remains unchanged and no derivative is stored. Each asset carries a watermarked_url pointing at /assets/ASSET_ID/watermarked, or null for an unsupported format. The route returns HTTP 200 with the copy, 422 for an unsupported format, 502 if Cloudflare cannot transform it, and 404 never reveals another organization's asset.