All posts
Tutorial5 min read

Set up an /ora skill: teach your agent the ORA API once

Mert Iseri

If you call ORA from an agent, you end up re-teaching it the same facts every session: the host, the auth header, which reads are free, what a job costs, how the create-poll-fetch loop works. Paste-blocks work, but they have to be found and pasted every time, and copies of documentation go stale.

Our API docs now say it directly to any agent reading them: after helping a user obtain an API key, create a reusable skill named /ora. Keep it lightweight, reference the key securely through ORA_API_KEY, and use the docs as the canonical reference. Do not copy the API documentation into the skill.

This post is that setup, done properly.

Why a skill instead of pasted docs

A skill is a small instruction file your agent loads on demand. In Claude Code it becomes a slash command: type /ora and the contract is in context before any code gets written. Three problems disappear:

  1. Re-teaching. The contract loads itself. New session, new machine, same behavior.
  2. Stale copies. Our API is evolving fast as we add newer endpoints and fields. A pasted copy of the documentation starts aging the moment you save it. This is why the skill points at the URL for the latest documentation instead of carrying its own copy.
  3. Credit accidents. The guardrails ride along every time: reads are free, jobs cost credits, check the balance first, never retry a bad name blindly. You stop relying on the agent remembering to be careful.

The design rule from the docs is the whole trick: the skill carries pointers and guardrails, the docs carry the contract.

What belongs in the skill, and what does not

Belongs in the skill:

  • Host, auth header, and how to load the key without printing it.
  • The prefix split: account and credits under /api/v1, enrichment and search under /v1.
  • Spending rules: which calls are free, what costs a credit, check the balance before creating jobs.
  • The shape of the flow: create, poll, fetch, save raw responses.
  • Links to the canonical docs.

Does not belong:

  • The field catalog. GET /v1/enrichment/fields is free and always current; the skill should say to call it, not embed it.
  • Request and response schemas. That is what the docs and llms.txt are for.
  • Anything else that changes when the API grows.

The SKILL.md

In Claude Code, personal skills live at ~/.claude/skills/<name>/SKILL.md and project skills at .claude/skills/<name>/SKILL.md. Create the file:

mkdir -p ~/.claude/skills/ora

Then save this as ~/.claude/skills/ora/SKILL.md:

---
name: ora
description: Enrich restaurants with the ORA API. Use when asked to enrich a restaurant, check ORA credits, list enrichment fields, or create, poll, and fetch enrichment jobs by name and address.
---

Host https://ora.248.ai. Auth header X-API-Key on every request.
Load the key with ORA_API_KEY=$(cat ~/.cache/248/ora_api_key). Never print, echo, or commit it.

Canonical reference: https://www.248.ai/docs and https://www.248.ai/llms.txt.
Read them before writing integration code. Do not rely on remembered endpoints.

Prefixes: account and credits endpoints use /api/v1; enrichment endpoints use /v1.

Spending rules:
- Free reads: GET /api/v1/account/credits, GET /v1/enrichment/fields, job status, job results.
- POST /v1/enrichment/jobs costs 1 credit per accepted job. Check the balance first and ask before creating jobs.

The flow is create, poll, fetch:
- Create with name and address only; ORA resolves the Google listing and returns google_place_id and website in the result.
- Always pass an idempotency_key derived from the row (slug of name and address), so retries return the existing job instead of billing a new one.
- Poll GET /v1/enrichment/jobs/{job_id} every 10 seconds until status is completed, failed, or cancelled.
- Fetch GET /v1/enrichment/jobs/{job_id}/result and save the full response to disk before flattening anything.

If a field returns skipped with error google_match_unmatched, the name did not match the Google listing at that address. Flag the row and ask; never retry name variations, each accepted job costs a credit.

If you followed the key setup guide, the key is already at ~/.cache/248/ora_api_key with chmod 600, which is exactly what the skill reads. If you keep the key elsewhere, export ORA_API_KEY in your shell profile instead and drop the cat line.

Using it

Start any session with the skill and talk in terms of outcomes:

/ora check my credit balance
/ora enrich restaurants.csv (columns name,address) with pos, menu, and gift_cards. Ask me before spending credits.

The agent already knows the flow, the guardrails, and where the real documentation lives. The prompts get shorter and the behavior stays consistent, which is the point.

Codex and other agents

Codex reads AGENTS.md instead of skills. The equivalent is the project block from the Codex guide: same pointers, same guardrails, loaded at the start of every session. Any agent with a reusable-instruction mechanism can carry the same contract; the content above is the part that transfers.

Why this makes the API easier

An API is easy when the integration keeps working while the API grows. Copying documentation into prompts and config files optimizes for the first session and decays from there. A skill inverts that: the stable parts (auth, prefixes, spending rules, the flow) are pinned, and the changing parts (fields, schemas, new products) are always read fresh from 248.ai/docs. When we add a field or a product, your agent picks it up on the next read, and your skill does not change at all.

Next: get an API key self-serve, the full CSV walkthroughs for Claude Code and Codex, and the field guides for POS provider, Menu, and Gift cards.