Write without fear
A write that times out leaves you guessing. Here's how to retry anything and never create it twice.
Why it matters
Did the contact get created? Did the text go out? Retrying without a key duplicates the row, and a send can be
delivered twice. Every mutation that honors it accepts an Idempotency-Key header: 1 to 255 characters, and a
UUID is ideal. Each operation’s reference page says whether it does.
How the gateway handles a key
The gateway reserves the key before it runs the operation and stores the response when it finishes. A retry
with the same key replays that stored response, marked Idempotency-Replayed: true, so a caller that timed out learns
what actually happened. Keys expire after 24 hours.
A key still in flight
If the first request hasn’t finished, a retry gets 409 idempotency_conflict. Wait, then retry with the same key.
A new key would run the write a second time.
When a key is handed back
When the gateway can prove a failure happened before the send started (bad variables, a Do-Not-Contact guard), it releases the key, so you can fix the request and retry with the same one.
A retry loop
KEY=$(uuidgen) # one key per logical write, reused on every retry
for attempt in 1 2 3; do
# --fail-with-body: a 409, 429 or 5xx is an HTTP failure, to retry with the same key.
if body=$(curl -sS --fail-with-body https://server.goliathdata.com/api/v1/call \
-H "Authorization: Bearer $GOLIATH_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $KEY" \
-d @create-contact.json); then
# A handled request is HTTP 200 even when the operation failed: read `errors` before calling it done.
# An operation error (bad input, a guard) is not retryable: the same request would fail the same way.
if echo "$body" | jq -e '(.errors // []) | length == 0' >/dev/null; then echo "$body"; exit 0; fi
echo "$body" >&2; exit 1
fi
sleep $((attempt * 2))
done
echo "gave up after 3 attempts" >&2
exit 1
// The SDK retries a keyed write itself, with the same key every time.
await goliath.contacts.createContact(
{ input: { sellerFirstName: 'Jane', sellerLastName: 'Doe' } },
{ idempotencyKey: crypto.randomUUID() },
)
Reads refuse the header
A read with an Idempotency-Key gets 400 bad_request instead of having it silently ignored, so the mistake shows up
on the first run. In the SDK, passing one on a read is a compile error.
Operations this guide covers: createContact, sendText, createDeal.