Authentication
Every request must include HMAC signature headers. Never call the Open API from a browser or frontend — keep the API secret on your backend only.
Auth header names remain X-Gwofy-* (legacy naming, matches the current Gooval backend — send headers exactly as listed below).
Credentials
Before integrating, obtain storeNumber (store ID) and apiSecret (API secret). Contact Gooval to enable access:
After onboarding, Gooval provides storeNumber and apiSecret (shown once — store immediately on your server; never commit to git or expose in the client).
| Credential | Usage | Postman / Apifox variable |
storeNumber | Header X-Gwofy-Store-Number | OPEN_API_STORE_NUMBER |
apiSecret | HMAC signing (not sent in headers) | OPEN_API_SECRET |
Headers
| Header | Required | Description |
X-Gwofy-Store-Number | Yes | Tenant store number |
X-Gwofy-Timestamp | Yes | Unix timestamp (seconds), ±5 minutes |
X-Gwofy-Signature | Yes | HMAC-SHA256 hex signature |
Content-Type | Yes | application/json |
Idempotency-Key | Write ops | Idempotency key; same key within 24h returns the same response |
Signature
message = storeNumber + "\\\\\\\\
" + timestamp + "\\\\\\\\
" + rawBody
signature = hex(hmac_sha256(apiSecret, message))
rawBody: raw HTTP request body string; empty string "" for GET
- Signature is lowercase hexadecimal
Environment variables
| Variable | Description |
OPEN_API_STORE_NUMBER | Store number |
OPEN_API_SECRET | API secret (server-side only) |
Reference data
GET
/open/v1/reference-data
Postman: List collections
List all reference-data collection names.
200 response
{
"schemaVersion": "2026.07.1",
"collections": [
"countries", "currencies", "carriers", "product-categories",
"destination-continent-categories", "goods-value-categories",
"certificate-types", "endorse-scenes", "cancel-reasons",
"claim-types", "policy-statuses", "claim-customer-statuses"
]
}
GET
/open/v1/reference-data/{collection}
Postman: Get reference data
Get enum items for a collection. Supports If-None-Match; returns 304 when unchanged.
Path parameters
| Parameter | Description |
collection | e.g. product-categories, cancel-reasons, endorse-scenes, claim-types |
200 example — cancel-reasons
{
"schemaVersion": "2026.07.1",
"collection": "cancel-reasons",
"items": [
{ "code": "merchantRefund", "name": "Merchant refund before shipment" },
{ "code": "duplicatePolicy", "name": "Duplicate policy" },
{ "code": "customerWithdraw", "name": "Customer withdrawal" },
{ "code": "other", "name": "Other" }
]
}
Policies
POST
/open/v1/policies/quote
Postman: Quote
Calculate premium from insured amount; does not create a policy. Same pricing as apply.
Quote does not require lineItems, orderPlacedAt, estimatedArrivalDate, or buyer.
Request body
| Field | Type | Required | Description |
externalReference | string | Yes | Merchant order ID |
risk.trackingNumber | string | Yes | Tracking number |
risk.insuredAmount | object | Yes | { amount, currencyCode } |
risk.destination | object | Yes | Destination address |
risk.departure | object | Yes | Origin address |
risk.carrierCode | string | No | 17track carrier code |
Example request
{
"externalReference": "ORD-1001",
"risk": {
"trackingNumber": "1Z999AA10123456784",
"carrierCode": "17",
"carrierName": "UPS",
"insuredAmount": { "amount": "180.00", "currencyCode": "USD" },
"destination": {
"countryCode": "US", "city": "Los Angeles",
"provinceCode": "CA", "addressLine": "123 Main St"
},
"departure": {
"countryCode": "CN", "city": "Shenzhen",
"addressLine": "Factory Zone A"
}
}
}
200 response
{
"externalReference": "ORD-1001",
"insuredAmount": { "amount": "180.00", "currencyCode": "USD" },
"premiumAmount": { "amount": "2.99", "currencyCode": "USD" },
"quoteExpiresInSeconds": 60
}
POST
/open/v1/policies/apply
Postman: Apply
Bind a policy on the Gooval platform after shipment. Returns policyNo immediately; reinsurance (if the catalog product is not self-retained) is submitted asynchronously and never exposed to merchants.
Requires Idempotency-Key header.
Key fields
| Field | Required | Description |
externalReference | Yes | Your order ID |
orderPlacedAt | Yes | ISO-8601 order time, e.g. 2026-08-20T09:15:00Z |
risk.trackingNumber | Yes | Tracking number |
risk.insuredAmount | Yes | Insured amount |
risk.destination / risk.departure | Yes | Address objects |
risk.estimatedArrivalDate | Yes | YYYY-MM-DD |
risk.lineItems | Yes | Merchandise breakdown (see below) |
buyer.name / buyer.email | Yes | Buyer contact; confirmation email contains spNumber |
attachments | No | Invoice / packing list / product photos (upload first) |
orderName | No | Display order name |
Example request
{
"externalReference": "ORD-1002",
"orderPlacedAt": "2026-08-20T09:15:00Z",
"orderName": "#1002",
"risk": {
"trackingNumber": "1Z999AA10123456784",
"carrierCode": "17",
"carrierName": "UPS",
"insuredAmount": { "amount": "180.00", "currencyCode": "USD" },
"estimatedArrivalDate": "2026-08-25",
"destination": {
"countryCode": "US", "city": "Los Angeles",
"provinceCode": "CA", "addressLine": "123 Main St, Los Angeles, CA"
},
"departure": {
"countryCode": "CN", "city": "Shenzhen",
"addressLine": "Factory Zone A"
},
"lineItems": [{
"itemId": "LINE-001", "sku": "TEE-BLU-M", "name": "Blue Tee",
"category": "apparel",
"quantity": 2,
"unitPrice": { "amount": "50.00", "currencyCode": "USD" },
"imageUrl": "https://cdn.merchant.com/tee.jpg"
}]
},
"buyer": { "name": "Jane Doe", "email": "alice@example.com" }
}
lineItems rules (required)
- Each line requires
name, category (from reference-data/product-categories), quantity (≥1), unitPrice, and at least one of sku or itemId
- Sum of
unitPrice × quantity must equal risk.insuredAmount (±0.01)
- Optional
imageUrl must be https
Omitting lineItems returns 400 field_required. Missing or unknown category returns field_required / invalid_enum. Legacy policies without line items fall back to a single virtual line at claim lookup.
If externalReference already has an active policy, apply returns 200 with error: duplicate_external_reference — use GET /policies?externalReference= or POST .../cancel before re-applying.
200 success (merchant-visible)
{
"policyNo": "P2026070612345678",
"externalReference": "ORD-1002",
"status": "active",
"premium": { "amount": "2.99", "currencyCode": "USD" },
"insuredAmount": { "amount": "180.00", "currencyCode": "USD" }
}
spNumber is never returned to merchants.
200 duplicate apply
{
"error": "duplicate_external_reference",
"message": "externalReference already has an active policy",
"field": "externalReference"
}
POST
/open/v1/policies/attachments/upload-url
Postman: Attachment upload URL
Get a presigned URL to upload policy attachments before apply.
POST /open/v1/policies/attachments/upload-url with { "contentType", "contentLength", "type"?, "fileName"? }
PUT the file to the returned uploadUrl (include the same Content-Type)
- Pass
attachmentKey on apply
Allowed types: invoice, packingList, productPhoto, other. Files: PDF / JPEG / PNG / WebP, 1 byte–5 MB, max 10 per apply. This route is not 24h-idempotent (presigned URLs expire in 900 seconds).
"attachments": [
{
"attachmentKey": "open-policy-attachments/{storeNumber}/{uuid}.pdf",
"type": "invoice",
"fileName": "invoice.pdf"
}
]
GET /policies/{policyNo} echoes orderPlacedAt and attachments (keys only; no download URL). Attachments are not sent to the reinsurer.
GET
/open/v1/policies
Postman: List policies
Query parameters
| Parameter | Default | Description |
cursor | — | Previous page nextCursor |
limit | 50 | 1–200 |
policyNo | — | Filter by policy number |
externalReference | — | Filter by order ID |
createdFrom / createdTo | — | ISO 8601 time range |
200 response
{
"items": [{
"policyNo": "P2026070612345678",
"externalReference": "ORD-1002",
"status": "active",
"orderName": "#1002",
"premium": { "amount": "2.99", "currencyCode": "USD" },
"createdAt": "2026-07-06T06:00:00+00:00"
}],
"nextCursor": "eyJ..."
}
GET
/open/v1/policies/{policyNo}
Get a single policy including orderPlacedAt and attachment keys.
GET
/open/v1/policies/{policyNo}/document
Get a pre-signed URL for the Gooval application confirmation PDF (documentType: confirmation). This is not an insurance policy.
Use ?lang=zh or ?lang=en (locale / language also accepted; default en). Reinsurer policy PDFs are not available on the Open API (source=policy returns 400 invalid_document_source).
{ "downloadUrl": "https://...", "expiresIn": 900, "documentType": "confirmation" }
POST
/open/v1/policies/{policyNo}/endorse
Postman: Endorse
Request body
| Field | Required | Description |
endorseScene | Yes | Supported scenes from reference-data/endorse-scenes (see table below) |
changes | Yes | Fields to change |
reason / remark | No | Notes |
endorseScene values
| Code | Mutable fields |
changeDestination | destination, claimPaymentAddress, destinationContinentCategory |
changeShipment | trackingNumber, carrierCode, sailDepartureDate, estimatedArrivalDate |
Example request
{
"endorseScene": "changeShipment",
"changes": {
"trackingNumber": "1Z999AA10987654321",
"carrierCode": "17"
},
"reason": "Carrier re-issued tracking label",
"remark": "Original label voided"
}
POST
/open/v1/policies/{policyNo}/cancel
Postman: Cancel
Request body
| Field | Required | Description |
cancelReasonCode | Yes | See cancel-reasons |
cancelReason | No | Reason text |
remark | No | Remark |
{
"cancelReasonCode": "merchantRefund",
"cancelReason": "Order refunded before shipment",
"remark": "Customer cancelled order ORD-1001"
}
200 response status is cancelled.
Outbound webhooks
Register your callback URL in the Merchant portal (seller.gooval.io), or contact contact@gooval.io.
Gooval POSTs JSON events to your URL. Payloads include policyNo and externalReference — never spNumber.
Webhook signature header remains X-Gwofy-Signature (legacy naming, matches backend).
Subscribed events
webhook.test · policy.insured · policy.failed · policy.endorsed · policy.cancelled · claim.submitted · claim.status_changed · claim.completed
When subscribedEvents is omitted, all event types above are delivered.
Verification
X-Gwofy-Signature = hex(hmac_sha256(webhook_secret, timestamp + "." + rawBody))
Postman mapping
| Request name | Method | Path |
| List policies (paginated) | GET | /open/v1/policies |
| List collections | GET | /open/v1/reference-data |
| Get reference data | GET | /open/v1/reference-data/claim-types |
| Cancel reasons | GET | /open/v1/reference-data/cancel-reasons |
| Quote | POST | /open/v1/policies/quote |
| Attachment upload URL | POST | /open/v1/policies/attachments/upload-url |
| Apply | POST | /open/v1/policies/apply |
| Get document | GET | /open/v1/policies/{policyNo}/document |
| Endorse | POST | /open/v1/policies/{policyNo}/endorse |
| Cancel | POST | /open/v1/policies/{policyNo}/cancel |
Environment example
{
"baseUrl": "https://sp-prod.gooval.io",
"OPEN_API_STORE_NUMBER": "100001",
"OPEN_API_SECRET": "<your-secret>"
}