# API
Source: https://docs.getmany.com/api
Learn how to automate your workflows with Getmany Service API
Getmany offers a comprehensive REST API that enables you to automate your entire Upwork workflow.
With our API, you can:
* Track proposal & profile analytics (views, replies, costs, response times)
* Retrieve jobs feed in real-time
* Integrate seamlessly with your existing tools and systems
For detailed API documentation, including authentication, rate limits, and available endpoints, please refer to our [API Reference](/api-reference/introduction).
# Get Agency Details
Source: https://docs.getmany.com/api-reference/endpoint/agency/get
GET /v1/agency
Returns the complete profile of the single agency linked to the authenticated workspace.
# List Agency Invitations
Source: https://docs.getmany.com/api-reference/endpoint/agency/invitations
GET /v1/agency/invitations
Retrieves agency invitations. Supports optional `status` filter and cursor pagination.
# List Agency Members
Source: https://docs.getmany.com/api-reference/endpoint/agency/members
GET /v1/agency/members
Retrieves agency members. Supports optional `role` filter and cursor pagination.
# Get Agency Proposal
Source: https://docs.getmany.com/api-reference/endpoint/agency/proposal
GET /v1/agency/proposals/{id}
Retrieves agency proposal.
# List Agency Proposals
Source: https://docs.getmany.com/api-reference/endpoint/agency/proposals
GET /v1/agency/proposals
Retrieves agency proposals. Supports optional `status` filter and cursor pagination.
# Cancel Bid
Source: https://docs.getmany.com/api-reference/endpoint/bid-intent/cancel
DELETE /v1/bid-intents/{id}
Cancels a scheduled bid intent by its ID
# List Chat Rooms
Source: https://docs.getmany.com/api-reference/endpoint/master-inbox/rooms
GET /v1/master-inbox/rooms
Returns a paginated list of chat rooms for the workspace's agency. Supports filtering by archived status, search, participants, pipeline stages, client-only messages, and multiple sort modes with cursor-based pagination.
# Send a Message
Source: https://docs.getmany.com/api-reference/endpoint/master-inbox/send-story
POST /v1/master-inbox/rooms/{roomId}/stories
Sends a plain-text message to a specific chat room via the Upwork messaging API. Requires an authorized freelancer who is a participant in the room. The workspace must have an active Master Inbox addon subscription, trial, or feature flag.
# List Chat Room Stories
Source: https://docs.getmany.com/api-reference/endpoint/master-inbox/stories
GET /v1/master-inbox/rooms/{roomId}/stories
Returns a paginated list of messages (stories) for a specific chat room. Supports cursor-based pagination and optional text search.
# Introduction
Source: https://docs.getmany.com/api-reference/introduction
Understand general concepts, response codes, and authentication strategies.
## Base URL
The Resend API is built on **REST** principles. We enforce **HTTPS** in every request to improve data security, integrity, and privacy. The API does not support **HTTP**.
All requests contain the following base URL:
```
https://api.getmany.io
```
## Authentication
To authenticate you need to add an *Authorization* header with the contents of the header being `Bearer gm_xxxxxxxxx` where `gm_xxxxxxxxx` is your [API Key](https://app.getmany.io/integrations/api).
```
Authorization: Bearer gm_xxxxxxxxx
```
## Response codes
Resend uses standard HTTP codes to indicate the success or failure of your requests.
In general, `2xx` HTTP codes correspond to success, `4xx` codes are for user-related failures, and `5xx` codes are for infrastructure issues.
| Status | Description |
| ------ | ---------------------------------------- |
| `200` | Successful request. |
| `400` | Check that the parameters were correct. |
| `401` | The API key used was missing. |
| `403` | The API key used was invalid. |
| `404` | The resource was not found. |
| `429` | The rate limit was exceeded. |
| `5xx` | Indicates an error with Getmany servers. |
## Rate limit
The default maximum rate limit is **20 requests per minute**. This number can be increased for trusted senders by request. After that, you'll hit the rate limit and receive a `429` response error code.
# Introduction
Source: https://docs.getmany.com/index
Getmany is your personal AI Sales Manager for Upwork Agency
## Learn
Discover the full range of features and capabilities.
Notify your applications and workflows about various events.
Integrate with our Service API for advanced use cases.
# Event Catalog
Source: https://docs.getmany.com/webhooks/event-catalog
List of supported event types and their payload.
### `proposal.accepted`
Occurs whenever the customer **accepts a proposal on Upwork**.
```json Request data sample icon="file-json" theme={null}
{
"proposal": {
"uid": "cf3e12b821",
"coverLetter": "Hi Duja team — I specialise in crafting memorable visual identities for emerging brands. Attached are two recent logo boards that show how I translate a story into colour, typography and iconography that work across print and social. I’d love to iterate on a first concept within 48 hours and can deliver the full brand-style guide in one week.",
"status": "SUBMITTED",
"createdAt": "2025-06-16T07:45:00Z"
},
"job": {
"slug": "~021908931246561901733",
"title": "Branding Specialist & Logo Design Needed",
"description": "Logo Design & Branding Specialist wanted to create a unique logo plus full branding package (brand colours, style guide, banners, social media assets and invitation cards). Must have a strong portfolio, be collaborative and able to translate brand values into compelling visuals.",
"createdAt": "2025-04-10T10:00:00Z"
},
"freelancer": {
"uid": "01921f906821a83980",
"name": "Valdas D.",
"photoUrl": "https://res.cloudinary.com/upwork-fp/image/upload/profile_photos/public/01921f906821a83980.jpg",
"slug": "~01921f906821a83980"
},
"manager": {
"uid": "0186bf9bc5f75be64d",
"name": "Duja Brand Ltd.",
"photoUrl": "https://assets.upwork.com/uploads/user/logo/default-logo.png",
"slug": "~0186bf9bc5f75be64d"
},
"chat": {
"id": "123456789"
}
}
```
### `chat.message.sent`
Occurs whenever the customer **sends you a new message in a conversation**.
```json Request data sample icon="file-json" theme={null}
{
"proposal": {
"uid": "cf3e12b821"
},
"message": {
"text": "Thanks for reviewing my proposal! Let me know which of the two draft concept directions resonates more and I’ll refine colour and typography tonight."
},
"chat": {
"id": "123456789"
}
}
```
### `bid_intent.scheduled`
Occurs whenever Auto-Bidder schedules a bid.
```json Request data sample icon="file-json" theme={null}
{
"jobUid": "cf3e12b821",
"bidId": "cf3e12b821"
}
```
# Managing Webhooks
Source: https://docs.getmany.com/webhooks/introduction
Use webhooks to notify your application about Upwork events.
## What is a webhook?
Getmany uses webhooks to push real-time notifications to you about your Upwork activity. All webhooks use HTTPS and deliver a JSON payload that can be used by your application. You can use webhook feeds to do things like:
* Update lead status based on changing proposal status
* Automatically handle new messages from customers
## Steps to receive webhooks
You can start receiving real-time events in your app using the steps:
1. Create a local endpoint to receive requests
2. Register your development webhook endpoint
3. Test that your webhook endpoint is working properly
4. Deploy your webhook endpoint to production
5. Register your production webhook endpoint
### 1. Create a local endpoint to receive requests
In your local application, create a new route that can accept POST requests.
For example, you can add an API route on Express.js:
```js index.ts theme={null}
import express from 'express';
const HTTP_PORT = 3000;
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
console.log("request payload", req.body);
res.json({ success: true });
});
app.listen(HTTP_PORT, () => {
console.log(`Example app listening on port ${HTTP_PORT}`);
});
```
On receiving an event, you should respond with an `HTTP 200 OK` to signal Getmany that the event was successfully delivered.
### 2. Register your development webhook endpoint
Register your publicly accessible HTTPS URL in the Getmany dashboard.
You can create a tunnel to your localhost server using a tool like
[ngrok](https://ngrok.com/download). For example:
`https://8733-191-204-177-89.sa.ngrok.io/api/webhooks`
### 3. Test that your webhook endpoint is working properly
Send a few test emails to check that your webhook endpoint is receiving the events.
### 4. Deploy your webhook endpoint
After you're done testing, deploy your webhook endpoint to production.
### 5. Register your production webhook endpoint
Once your webhook endpoint is deployed to production, you can register it in the Getmany dashboard.
## FAQ
If Getmany does not receive a 200 response from a webhook server, we will retry the webhooks.
Each message is attempted based on the following schedule, where each period is started following the failure of the preceding attempt:
* 5 seconds
* 5 minutes
* 30 minutes
* 2 hours
* 5 hours
* 10 hours
After the conclusion of the above attempts the message will be marked as failed, and you will get a webhook of type `message.attempt.exhausted` notifying you of this error.
If your server requires an allowlist, our webhooks come from the following IP addresses:
* `52.215.16.239`
* `54.216.8.72`
* `63.33.109.123`
* `2a05:d028:17:8000::/56`
# Verify Webhooks Requests
Source: https://docs.getmany.com/webhooks/request-validation
Learn how to use the signing secret to verify your webhooks.
## Why should I verify webhooks?
Webhooks are vulnerable because attackers can send fake HTTP POST requests to endpoints, pretending to be legitimate services. This can lead to security risks or operational issues.
To mitigate this, each webhook and its metadata are signed with a unique key specific to the endpoint. This signature helps verify the source of the webhook, allowing only authenticated webhooks to be processed.
Another security concern is replay attacks, where intercepted valid payloads, complete with their signatures, are resent to endpoints. These payloads would pass the signature verification and be executed, posing a potential security threat.
## Verify webhooks in your app
To verify the webhook request, you have to use the secret and deconstruct the Svix headers, and Base64-decode the Getmany secret. The example below is for Javascript. [Learn more and view all supported languages here.](https://docs.svix.com/receiving/verifying-payloads/how)
First, install the Svix libraries.
```sh npm theme={null}
npm install svix
```
```sh yarn theme={null}
yarn add svix
```
```sh pnpm theme={null}
pnpm add svix
```
Then, verify the webhooks using the code below. The payload is the raw (string) body of the request, and the headers are the headers passed in the request.
Make sure that you're using the raw request body when verifying webhooks,
since the cryptographic signature is sensitive to even the slightest change.
Watch out for frameworks that parse the request as JSON and then stringify it,
since this too will break the signature verification.
```js theme={null}
import { Webhook } from 'svix';
const secret = process.env.WEBHOOK_SECRET;
// These were all sent from the server
const headers = {
'svix-id': 'msg_p5jXN8AQM9LWM0D4loKWxJek',
'svix-timestamp': '1614265330',
'svix-signature': 'v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=',
};
const payload = '{"test": 2432232314}';
const wh = new Webhook(secret);
// Throws on error, returns the verified content on success
wh.verify(payload, headers);
```
If you prefer, you can also [manually verify the headers as well.](https://docs.svix.com/receiving/verifying-payloads/how-manual)